移除链表元素
链接: 移除链表元素
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* removeElements(struct ListNode* head, int val) { //设置俩个指针 //prev用来记录val前面的指针 //假设将prev的指向head的前面,即为NULL struct ListNode* prev = NULL; //cur用来判断,cur指向链表第一个 struct ListNode* cur = head; //利用prev和cur进行循环 //当cur为NULL停止 while(cur != NULL) { if(cur->val != val) { //cur的值不等于val时 //prev向后移动一步 //cur向后移动一步 prev = cur; cur = cur->next; } else { //判断如果一个值为val时,此时prev任然为NULL; //需要将这种cur向后移 if(prev == NULL) { //将head指向下一个 head = cur->next; //释放cur free(cur); //cur重新指向head的值 cur = head; } else { //cur的值等于val时 //将prev指向的地址向后移动一步 prev->next = cur->next; //释放cur所在的内存 free(cur); //将粗人指向新的prev后面的位置 cur = prev->next; } } } return head; }
链表的中间结点
链接: 链表的中间结点
思路:使用快慢指针进行解答
1.定义一个快指针和慢指针均指向头指针
2.快指针一次走俩步,慢指针一次走一步
3.当快指针为空指针或者快指针的下一个指针为空时结束
代码详解:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* middleNode(struct ListNode* head) { //定义一个快指针,一次走俩格 struct ListNode* fast = head; //定义一个慢指针,一次走一格 struct ListNode* slow = head; while(fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; } return slow; }
返回倒数第k个结点
链接: 返回倒数第k个结点
思路:使用先后指针解答
1.定义一个先走指针fast和慢走指针slow
2.先走指针要比慢走指针快k步
3.然后俩个指针同时进行移动
4.当先走指针遇到NULL时停止
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ int kthToLast(struct ListNode* head, int k) { //定义一个先走指针, struct ListNode* fast = head; //定义一个慢走指针 struct ListNode* slow = head; //先走指针比慢走指针快k步 while(k--) { fast = fast->next; } //俩个指针一起走 while(fast != NULL) { fast = fast->next; slow = slow->next; } return slow->val; }
合并俩个有序链表
链接:合并俩个有序链表
思路:
1.定义cur1指向list1的头结点,定义cur2指向list2的头结点,定义head和end指向空
2.cur1用来遍历list1,cur2用来遍历list2,head用来记录合并后的头结点,end用来记录合并后的尾结点,以确保可以向后添加结点
3.判断是否有空,但凡有一个为空,就可以返回另外一个;如果俩个都不为空,需要设置合并后的头结点head
4.当俩个都不为空,进入循环,向end后面接结点
5.当俩个中间有一个为空时,可以只在将另一个接在end后面
代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { //设置四个结点 struct ListNode* cur1 = list1; struct ListNode* cur2 = list2; struct ListNode* head = NULL; struct ListNode* end = NULL; //判断如何都不为空 if (cur1 && cur2) { //将合并后头结点head指向小值 if (cur1->val < cur2->val) { head = end = cur1; cur1 = cur1->next; } else { head = end = cur2; cur2 = cur2->next; } } //cur1与cur2都不为空所以不需要判断else,如果没有else,设置完头结点head后,有一个可能为空,导致返回。 else if (cur1 == NULL)//cur1为空,返回cur2 { return cur2; } else if (cur2 == NULL)//cur2为空。返回cur1 { return cur1; } //俩个都不为空进行插入链表 while (cur1 && cur2) { //每次插入都需要,将cur和end向后移动 if (cur1->val <= cur2->val) { end->next = cur1; cur1 = cur1->next; end = end->next; } else { end->next = cur2; cur2 = cur2->next; end = end->next; } } //如果其中一个为空,可以直接将另一个后面的全部接在end后面 if (cur1 == NULL) { end->next = cur2; } if (cur2 == NULL) { end->next = cur1; } return head; }
链表分割
链接:链表分割
思路:
1.首先需要创建俩个哨兵结点来将大值结点与小结点分割开
2.使用四个指针指向俩个哨兵结点,begin1、begin2、end1、end2
3.begin1与begin2保留俩个哨兵结点的位置,end1与end2接后面的结点
4.然后将俩个哨兵结点相连,注意需要释放空间
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class Partition { public: ListNode* partition(ListNode* pHead, int x) { //创建俩个哨兵结点 //使用begin1与end1指向第一个哨兵 //使用begin2与end2指向第二个哨兵 struct ListNode* begin1; struct ListNode* begin2; struct ListNode* end1; struct ListNode* end2; begin1 = (struct ListNode*)malloc(sizeof(struct ListNode)); begin2 = (struct ListNode*)malloc(sizeof(struct ListNode)); if(begin1 == NULL || begin2 == NULL) { perror("malloc fail"); return NULL; } begin1->next = NULL; begin2->next = NULL; end1 = begin1; end2 = begin2; //将小于x的结点接在begin1后面 //将大于等于x的结点接在begin2后面 while(pHead != NULL) { if(pHead->val < x) { end1->next = pHead; end1 = end1->next; } else { end2->next = pHead; end2 = end2->next; } pHead = pHead->next; } //将end1与end2后面置空 end1->next = NULL; end2->next = NULL; //将大于等于x的结点接在小于x的结点后面 end1->next = begin2->next; //将小于x的第一个结点设置为头结点 pHead = begin1->next; //注意需要释放malloc创建的堆区已经野指针问题 free(begin1); free(begin2); begin1 = begin2 = end1 = end2 = NULL; return pHead; } };
相交链表
链接: 相交链表
思路:
1.定义俩个指向链表的指针和俩个计算结点个数(长度)的变量
2.求出俩个链表有几个结点,即链表的长度
3.如果最后一个结点处,二者并没有相交,则返回NULL
4.将俩个链表的结点个数(长度)相减,让结点个数(长度)多(长)的先走相减的个数。
5.最后俩条链表同时走,遇到相同结点时结束
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { //设置L1和L2计算俩条链的长度 int L1 = 1, L2 = 1; //设置俩个指针指向俩条链的头结点 struct ListNode* cur1 = headA; struct ListNode* cur2 = headB; //计算L1的长度 while(cur1->next != NULL) { cur1 = cur1->next; ++L1; } //计算L2的长度 while(cur2->next != NULL) { cur2 = cur2->next; ++L2; } //判断如果俩个直接的最好交点不在一起则直接返回NULL if(cur1 != cur2) { return NULL; } //计算链的长度差 int L = L1 - L2; //将移动的指针重新指向头结点 cur1 = headA; cur2 = headB; //让长度较长的指针先走L步 if(L > 0) { while(L--) { cur1 = cur1->next; } } else { while(L++) { cur2 = cur2->next; } } //俩个指针同时走,发现相同时停止 while(cur1 != cur2) { cur1 = cur1->next; cur2 = cur2->next; } return cur1; }
环形链表
链接: 环形链表
思路:
1.判断是否存在空结点和只有一个结点的情况
2.定义一个快结点和一个慢结点
3.快结点一次走俩步,慢结点一次走一步
4.当二者相遇时结束
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ bool hasCycle(struct ListNode *head) { //判断是否存在空链表或者链表中只存在一个结点 if(head == NULL || head->next == NULL) { return false; } //定义一个快结点和慢结点 struct ListNode* fast = head; struct ListNode* slow = head; //快结点一次走俩步 //慢结点一次走一步 while(fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; //相遇时结束 if(fast == slow) { return true; } } return false; }
链表的回文结构
链接: 链表的回文结构
思路:
1.判断当存在空链表或者当个链表时返回true
2.设置快慢指针求得中间结点
3.使用三个指针翻转后半段链表
4.使用一前一后俩个指针判断是否为回文结构
难点:使用三个指针翻转链表时,循环停止的条件为中间的指针为空,此时需要第三个结点在循环内初始化,这样才能保证后面每一个链表都能翻转过来,并且当第三个结点为空时,不会执行next
- 代码实现:
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class PalindromeList { public: bool chkPalindrome(ListNode* A) { //链表为空或者链表只有一个返回true if(A == NULL || A->next == NULL) { return true; } //设置快慢指针 //快指针一次走俩步 //慢指针一次走一步 struct ListNode* fast = A; struct ListNode* slow = A; //寻找中间结点 while(fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; } //slow此时所在位置为中间结点 //从中间结点往后开始翻转链表 struct ListNode* cur = slow->next; while(cur != NULL) { struct ListNode* cur_next = cur->next; cur->next = slow; slow = cur; cur = cur_next; } //设置一个头结点和尾结点 struct ListNode* tail = slow; struct ListNode* head = A; //一前一后开始比较 //比较正确,比较下一个 //比较错误,返回错误 while( head != tail)//奇数时二者相遇 { if(head->val != tail->val) { return false; } if(head->next == tail) { //偶数时head的下一个是tail return true; } head = head->next; tail = tail->next; } return true; } };