链表是面试常考问题
结构:
由指针把若干个节点连接成链状结构
包括创建、插入、删除等操作
链表是一种动态数据结构,是因为在创建链表时,无需知道链表长度
当插入一个节点时,我们只需要微信节点分配内存,然后调整指针的指向来确保新节点被连接到链表中
内存分配不是在创建链表时一次性完成的,而是每添加一个节点分配一次内存
没有闲置的内存
单向链表的节点定义:
class ListNode{
int value;
ListNode nextNode;
}
往该链表的末尾添加一个节点的代码:
class ListNode {
int value;
ListNode nextNode;
ListNode(int x) { value = x; }
}
public class linkedList{
public static void addToTail(ListNode pHead,int value){
ListNode pNew=new ListNode(value);
pNew.nextNode=null;
if (pHead == null) {
pHead=pNew;
}
else{
ListNode pNode=pHead;
while(pNode.nextNode!=null){
pNode=pNode.nextNode;
}
pNode.nextNode=pNew;
}
}
}
第一个参数pHead是指向指针的指针。当我们往一个空链表中插入一个节点时,新插入的节点就是链表的头指针
由于此时会改动头指针,因此必须把pHead参数设为指向指针的指针,否则除了这个函数pHead仍然是一个空指针
链表中的内存不是一次性分配的,无法保证链表的内存连续,因此如果想在链表中找到它的第i个节点,那么我们只能从头节点开始,沿着指向下一个结点的指针遍历链表,他的时间效率为O(n)。而在数组中,我们可以根据下标在O(1)时间内找到第i个元素
在链表中找到第一个含有某值的节点并删除该节点的代码
public static void removeNode(ListNode pHead ,int value){
//如果头节点是空的
if(pHead==null||pHead==null){
return;
}
//初始化删除节点
ListNode pToBeDeleted=null;
//遍历链表如果链表头节点值确定
if(pHead.value==value){
//删除节点变为当前节点
pToBeDeleted=pHead;
//头节点下移
pHead=pHead.nextNode;
}
//如果链表节点值不与目标值相同
else{
ListNode pNode=pHead;
//当头节点不为空
while(pNode.nextNode!=null&&pNode.nextNode.value!=value){
//移动到下一节点
pNode=pNode.nextNode;
}
//如果下一节点值与目标值相同
if(pNode.nextNode!=null&&pNode.nextNode.value==value){
pToBeDeleted=pNode.nextNode;
//把目标节点断开,上一节点指向目标节点的下一节点
pNode.nextNode=pNode.nextNode.nextNode;
}
}
//消除目标节点
if(pToBeDeleted!=null){
pToBeDeleted=null;
}
}
面试题6.从头到尾打印链表
题目:输入一个链表的头节点,从尾到头反过来打印出每个节点值
遍历链表
后进先出->用栈
public class printReversedList {
public static void printReversedList(ListNode pHead){
Stack<ListNode> nodes = new Stack<>();
ListNode pNode=pHead;
//遍历链表把链表中的值全部顺序放入栈中
while(pNode!=null){
nodes.push(pNode);
pNode=pNode.nextNode;
}
//当栈中有值顺序弹出
while(!nodes.empty()){
pNode=nodes.peek();
System.out.print(pNode.value+" ");
nodes.pop();
}
}
public static void main(String[] args){
ListNode officers = new ListNode(1);
ListNode pHead=officers;
for(int i=2;i<=5;i++){
officers.nextNode = new ListNode(i);
officers=officers.nextNode;
}
printReversedList(pHead);
}
}
上述很简洁,但是链表很长的时候调用很深,可能导致函数调用栈溢出。