hello,大家好,本文在上文单链表的基础上,继续探讨单链表的一些常见算法题,同样,本文所用语言为C语言,话不多说,开讲吧!
删除链表的倒数第N个节点
此题为LeetCode算法第19题,可采用双指针算法求解,同时引入虚拟头节点简化边界处理,具体代码及算法描述如下:
struct LinkList{int val;struct LinkList *next;};void removeNthFromEnd(struct LinkList **head, int N){// 定义虚拟头节点方便边界处理struct LinkList *dummy = (struct LinkList *)malloc(sizeof(struct LinkList));if(dummy == NULL){printf("哦豁,内存分配失败辽...\n");exit(1);}dummy->val = -1;dummy->next = *head;// 定义双指针struct LinkList *pre = dummy;struct LinkList *cur = *head;// cur指针先走 N个节点,此时cur与 pre之间间隔 N个节点for(int i = 0; i < N; ++i){cur = cur->next;}// 同步移动双指针直到cur指针到达单链表尾节点while(cur != NULL){cur = cur->next; // 循环退出时cur指向NULLpre = pre->next; // 循环退出时pre指向倒数第 N+1个节点}// 删除倒数第N个节点,释放堆空间struct LinkList *temp = pre->next;pre->next = pre->next->next;*head = dummy->next;free(dummy);free(temp);}
上述程序的运行结果如下:

两两交换链表节点
此题为LeetCode算法第24题,涉及到多个链表指针操作时,苦思冥想一小时不如纸上画图两分钟来得快,同样此题定义虚拟头节点,每次让虚拟头节点移动两个节点的位置,直到链表结束或者剩一个节点为止,下图为此题算法思路示意

代码如下
void swapPairsLinkList(struct LinkList **head){// 定义虚拟头节点方便边界处理struct LinkList *dummy = (struct LinkList *)malloc(sizeof(struct LinkList));if(dummy == NULL){printf("哦豁,内存分配失败辽...\n");exit(1);}dummy->val = -1;dummy->next = *head;struct LinkList *cur = dummy;while(cur->next && cur->next->next){// 定义cur的后两个节点struct LinkList *node1 = cur->next;struct LinkList *node2 = cur->next->next;// 交换cur节点的后两个节点cur->next = node2;node1->next = node2->next;node2->next = node1;// 一次移动两个节点位置cur = node1;}*head = dummy->next;free(dummy);}
上述代码的运行结果如下:

K个一组反转链表
此题为LeetCode算法第25题,算法思路如下:
特殊情况优先处理:链表为空、链表只有一个节点、k==1
计算链表长度,若链表长度小于k,直接返回即可
翻转k个链表节点(参考翻转单链表中反转链表部分,经典三指针翻转)
链接翻转前后的指针,递归进行下一次翻转
下图为上述算法思路示意图

上述算法的代码如下:
struct LinkList *reverseKGroup(struct LinkList **head, int k){// 特殊情况首先处理if(*head == NULL || (*head)->next == NULL || k == 1)return *head;// 计算链表长度int len = 0;struct LinkList cur = *head;while(cur != NULL){len ++;cur = cur->next;}// 若链表长度小于k,直接返回链表if(k > len) return *head;cur = *head;struct LinkList *node1 = NULL, *node2 = *head;// K个一组进行翻转,常规三指针法for(int i = 0; i < k; ++i){struct LinkList *temp = node2->next;node2->next = node1;node1 = node2, node2 = temp;}// K个一组翻转后,node2为下一组待翻转的头节点// node1为已翻转组的头节点// 链接翻转后的链表,递归进行下一次翻转cur->next = reverseKGroup(&node2, k);return node1;}
上述代码的运行结果如下

删除链表重复元素Ⅰ
此题为LeetCode算法第83题,可通过一次遍历,若下一节点数值等于当前节点数值,直接跳过下一节点即可,代码如下:
void deleteDuplicates1(struct LinkList **head){if(*head == NULL || (*head)->next == NULL) return ;struct LinkList *cur = *head;while(cur->next){// 若节点值重复 则跳过下一节点if(cur->val == cur->next->val){cur->next = cur->next->next;}else{cur = cur->next;}}}
上述代码的运行结果如下:

删除链表重复元素Ⅱ
此题为LeetCode算法第82题,与上一题不同的是,需要将重复元素斩草除根,由于头节点也可能被删除,因此引入虚拟头节点方便处理,代码如下:
void deleteDuplicates2(struct LinkList **head){// 特殊情况优先处理if(*head == NULL || (*head)->next == NULL) return ;// 创建虚拟头节点,方便头节点重复的处理struct LinkList *dummy = (struct LinkList *)malloc(sizeof(struct LinkList));if(dummy == NULL){printf("哦豁,内存分配失败了,,,\n");exit(1);}dummy->val = 0;dummy->next = *head;struct LinkList *cur = dummy;while(cur->next && cur->next->next){// 遇到重复节点if(cur->next->val == cur->next->next->val){int num = cur->next->val;// 循环跳过所有重复节点while(cur->next && cur->next->val == num){cur->next = cur->next->next;}}else{cur = cur->next;}}*head = dummy->next;free(dummy);}
下图为上述程序运行结果

单链表插入排序
本题为LeetCode算法第147题,单链表插入排序算法与数组一致,从前往后遍历链表节点,将每一个节点插入到链表的合适位置即可,下图为算法示意图

上述算法思路代码如下:
void insertionSort(struct LinkList **head){if(*head == NULL || (*head)->next == NULL) return ;struct LinkList *dummy = (struct LinkList *)malloc(sizeof(struct LinkList));if(dummy == NULL){printf("哦豁,内存分配失败辽...\n");exit(1);}dummy->val = 0;dummy->next = NULL;struct LinkList *cur = *head;struct LinkList *pre = dummy;while(cur){// 循环退出时,pre指向插入位置的上一节点while(pre->next && pre->next->val <= cur->next){pre = pre->next;}// 将cur节点插入到 pre节点后面struct LinkList *temp = cur->next;cur->next = pre->next;pre->next = cur;// 每次插入完毕后,更近pre,方便下一次节点的插入pre = dummy;// cur指向下一个插入节点cur = temp;}*head = dummy->next;free(dummy);}
上述代码的运行结果如下:

后记
分析上述算法题,可以发现处理链表题的一些技巧:
定义虚拟头节点方便边界处理
画图分析链表结构,否则很容易导致指针指向混乱
将当前处理节点、上一节点以及下一节点定义出来,方便指针分析
讲完啦,才发现新申请的公众号并没有留言功能
,欢迎大家勘误或提出有效建议(邮箱号:seuhyz@163.com),欢迎大家分享转发,谢谢大家!





