🔥博客主页:小王又困了
📚系列专栏:数据结构
🌟人之为学,不日近则日退
❤️感谢大家点赞👍收藏⭐评论✍️
目录
一、移除链表元素
💡方法一:
💡方法二:
二、链表的中间节点
💡方法一:
三、链表中倒数第k个结点
💡方法一:
四、反转链表
💡方法一:
💡方法二:
五、合并两个有序链表
💡方法一:
🗒️前言:
在上一期中我们给大家介绍了单链表,也了解了单链表的实现。接下来就让我们进入实践,练习一些经典题目,让我们对单链表的理解更加深入。
一、移除链表元素
题目:
💡方法一:
我们使用两个指针遍历数组,遇到与 val 相同的数据域,就删除这个节点。我们在思考问题时要想全面,当要删除头节点时,常规方法就无法实现,对于删除头节点要做单独处理。
🍩常规删除:
🍩头节点删除
struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode* prev=NULL;struct ListNode* cur=head;while(cur!=NULL){//删除if(val==cur->val){//头删if(cur==head){head=cur->next;free(cur);cur=head;}//常规else{prev->next=cur->next;free(cur);cur=prev->next;}}//遍历else{prev=cur;cur=cur->next;}}return head; }
💡方法二:
我们通过遍历,把节点的数据域不等于val的节点尾接到新的链表中。我们要考虑第一个节点是不是要删除的。最后一个节点的指针域置空要放在循环结束后,判断tail是否为空指针。
struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode* newhead=NULL;struct ListNode* tail=NULL;struct ListNode* cur=head;while(cur){if(cur->next==val){//删除struct ListNode* del=cur;cur=cur->next;free(del);}else{//尾插if(tail==NULL){newhead=tail=cur;//tail=cur;}else{tail->next=cur;tail=tail->next; }cur=cur->next;}}if(tail){tail->next=NULL;}return newhead; }
二、链表的中间节点
题目:
💡方法一:
我们可以定义两个指针,快指针一次走两步,慢指针一次走一步,当快指针走到结尾时,慢指针正好走了一半,这样我们就可以找到中间节点。
struct ListNode* middleNode(struct ListNode* head) {struct ListNode* fast=head;struct ListNode* slow=head;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;}return slow; }
三、链表中倒数第k个结点
题目:
💡方法一:
我们可以参考上一题的方法,同样定义快慢指针,想让快指针走k步,然后在同时走,走到fast为空指针就找了倒数第k个节点。有可能链表没有k个节点,所以我们要加入判断。
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {struct ListNode* fast=pListHead;struct ListNode* slow=pListHead;while(k--){//链表没有k步长if(fast==NULL){return NULL;}fast=fast->next;}while(fast!=NULL){fast=fast->next;slow=slow->next;}return slow; }
四、反转链表
题目:
💡方法一:
我们定义三个指针n1,n2,n3,来改变节点链接的顺序。将头节点变为尾节点,当n2为空指针时,n1就为链表的头节点,只需返回n1就可以。两个指针倒方向,一个指针保持下一个。
struct ListNode* reverseList(struct ListNode* head) {struct ListNode* n1=NULL;struct ListNode* n2=head;struct ListNode* n3;if(n2){n3=n2->next;}while(n2){n2->next=n1;//往后走n1=n2;n2=n3;if(n3){n3=n3->next;}}return n1; }
💡方法二:
将链表的节点一个一个拿下来,进行头插。这里要注意赋值的顺序。
struct ListNode* reverseList(struct ListNode* head) {struct ListNode* cur=head;struct ListNode* newnode=NULL;while(cur){//保存节点struct ListNode* next=cur->next;//头插cur->next=newnode;newnode=cur;cur=next;}return newnode; }
五、合并两个有序链表
题目:
💡方法一:
我们创建一个带哨兵位的链表,这样在尾插时就不用判断是否是第一个节点,可以提高效率。要记住在最后要将哨兵位的空间释放。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if(list1==NULL){return list2;}if(list2==NULL){return list1;}struct ListNode* head=NULL;struct ListNode* tail=NULL;//创建一个哨兵位head=tail=(struct ListNode*)malloc(sizeof(struct ListNode));while(list1&&list2){if(list1->val<list2->val){tail->next=list1;tail=tail->next;list1=list1->next;}else{tail->next=list2;tail=tail->next;list2=list2->next;}}if(list1){tail->next=list1;}if(list2){tail->next=list2;}struct ListNode* del=head;head=head->next;free(del);return head; }
本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。你们的支持就是博主最大的动力。