单链表的各种操作 笔试 面试

一、链表与数组的 差别
1、逻辑结构   数组必须事先定义固定的长度  不能动态的增减   链表是动态分配内存
2、内存结构   数组从栈中分配空间   链表在堆中
3、数组在内存中顺序存储   链表随机存储    数组訪问效率高   链表插入删除方便
4、数组存在越界问题 


定义表头。 为方便操作 表头数据域为空
二、单链表插入 删除
bool insertList(List head, Type x, int index){


Node *p;
p = head;
int j = 1;
while(p->next&& j < index){
p = p->next;
++j;
}
if(p==NULL) return ERROR;
Node *tmp = (Node *)malloc(sizeof(Node));
tmp->data = x;
tmp->next = p->next; //tmp的后继指向原index位置的结点
p-next = tmp; //p的后继为新结点
return OK;
}
bool deleteList(List head, int index){
Node *p = head;
int j = 1;
while(p->next!=NULL&&j < i){
p = p->next;
++j;
}// p->next为第index个
if(p==NULL || p->next==NULL || j > i) return ERROR; //i可能为负值
Node *tmp = p->next; //tmp指向第index个
p->next = tmp->next; //第index+1个取代index
free(tmp);//释放空间
return OK;
}


三、找出单链表中的倒数第k个元素
解题思路
1、先遍历一遍 计算长度。 再找出后k个
2、双路齐下  p1从第一位開始。p2从第k为開始遍历  直到p2走到头
思路2代码:
Node* find(Node* head, int index){
Node *p1,*p2;
p1 = head;
p2 = head;
for(int i = 0; i < index; i++){ 
p2 = p2->next; //p2向后移k位
}
while(p2!=NULL){
p1 = p1->next;
p2 = p2->next;
}
return p1;
}


四、单链表反转
解题思路:每次操作结点时  标注其前结点 后结点  对其进行操作
Node* reverse(Node *head){
Node *prev = NULL;
Node *pCur = head;
Node *rHead = NULL;


while(pCur!=NULL){
Node *pNext = head->next;
if(pNext == NULL)
    rHead = pCur;
pCur->next = prev; //改变顺序  当前结点指向 自己的前一个结点
prev = pCur; //当前结点变为前结点 (为了下一个结点准备)
pCur = pNext; //结点后移
}
}


五、从尾到头输出单链表
1、递归输出
2、非递归输出
非递归操作  : 
1).能够使用 “四” 的代码进行反转  然后输出
2).遍历结点入栈 然后输出


六、寻找单链表的中间结点
1、遍历求长度length  然后再遍历输出
2、双路齐下   p1走一步 p2走两步 p2走到终点时 p1正好到中点
Node* findMiddle(Node *head){
Node *p1 = head;
Node *p2 = head;
while(p2->next->next!=NULL){
p2 = p2->next->next;
p1 = p1->next;
}
return p1;
}
七、单链表排序
与数组排序差别不大,交换元素时 仅仅交换数据域的内容就好。链表的顺序结构不用变化


八、单链表中随意 交换两个元素 (要注意表头)
将2个结点进行交换 要注意 next指针的 交换问题
//将p q结点交换
Node* swap(Node* head,Node* p,Node* q){
if(head==NULL || p==NULL ||  q==NULL){
Print(ERROR);
return head;
}
if(p==q){
Print(OK);
return head;
}
else if(p->next == q){ //两节点相邻
Node* prev = getPrev(p);
p->next = q->next;
q->next = p;
prev->next = q;
}
else if(q->next == p){
Node* prev = getPrev(q);
q->next = p->next;
p->next = q;
prev->next = p;
}
else if(p!=q){ //两节点不相邻 且不同  交换前后指针域
Node* prev1 = getPrev(p);
Node* prev2 = getPrev(q);
Node* next1 = p->next;
Node* next2 = q->next;
p->next = next2;
prev2->next = p;
q->next = next1;
prev1->next = q;
}
return head;
}




九、检測一个较大的单链表是否有环
双路齐下法  一个走一步一个走2步 看是否会相遇


十、推断两个(无环)单链表是否交叉
推断最后一个结点是否同样


十一、删除单链表中的反复结点
哈希, 建议一hash_map ,遍历链表 若结点出现反复则删除


十二、合并两个有序链表(非交叉)
1、递归
Node* Merge(Node* head1, Node* head2){
if(head1==NULL)
return head2;
if(head2==NULL)
return head1;
Node* head=NULL;
if(head1->data < head2->data){
head = head1;
head->next = Merge(head1, head2);
}else {
head = head2;
head->next = Merge(head1, head2);
}
return head;
}
2、非递归
Node* Merge(Node*head , Node* head1, Node* head2){
Node* tmp = head;
while(head1!=NULL&&head2!=NULL){
if(head1->data < head2->data){ 
tmp->next = head1;//指向head1当前结点
tmp = head1;//移动tmp的位置
head1 = head1->next;//head1后移
}else {
tmp->next = head2;
tmp = head2;
head2= head2->next;
}
}
if(head1==NULL)
tmp->next = head2;
if(head2==NULL)
tmp->next = head1;
return head;
}
原文地址:https://www.cnblogs.com/tlnshuju/p/7061220.html