0


玩转链表,从这8道经典链表oj题开始

文章目录

1.移除链表元素

在这里插入图片描述
大体思路分析:用

cur

指针去遍历链表,用

prev

指针记录

cur

的前一个节点,如果

cur->val != val

,则

prev=cur,cur=cur->next

;如果

cur->val == val

,则用

next

指针记录

cur

指针的下一个节点,

free(cur),prev=next,cur=next,prev=cur;

继续如此循环。
但是如果第一个链表的数据就是

val

就又是一种情况。如果连续几个都是

val

又是什么情况呢?
下面我们画图来分析。

  1. 常规情况: 在这里插入图片描述
  2. 连续几个val: 在这里插入图片描述 我们发现常规情况也能处理连续几个val的情况。
  3. 第一个就是val,意味着要改变头指针 在这里插入图片描述

代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */struct ListNode*removeElements(struct ListNode* head,int val){struct ListNode* cur = head;struct ListNode* prev =NULL;while(cur){if(cur->val != val){
            prev = cur;
            cur = cur->next;}else{struct ListNode* next = cur->next;if(prev ==NULL){free(cur);
                head = next;
                cur = next;}else{free(cur);
                prev->next = next;
                cur = next;}}}return head;}

2. 反转链表

在这里插入图片描述

2.1 三指针翻转法

令指针

n1

等于

NULL

,

n2

等于

head

,

n3

记录

n2

的下一个,让

n1,n2

去倒指针的方向,

n3

记录下一个节点。
在这里插入图片描述
我们发现当

n2

指针等于

NULL

时,链表全部反转,所以

n2 == NULL

为结束条件。
特殊情况:
在这里插入图片描述
此时

n3

已经为

NULL

了,如果继续

n3=n3->next

,就出现了访问空指针的情况。所以这种情况也要判断一下。另外,如果头指针为

NULL

,直接

return NULL


代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */struct ListNode*reverseList(struct ListNode* head){if(head ==NULL)returnNULL;struct ListNode* n1,*n2,*n3;
    n1 =NULL;
    n2 = head;
    n3 = n2->next;while(n2){
        n2->next = n1;
        n1 = n2;
        n2 = n3;if(n3){
            n3 = n3->next;}}return n1;}

2.2 头插法

cur

取原链表节点,头插到

newHead

所在的链表,用

next

指针记录

cur

的下一个,同时更新

newHead


在这里插入图片描述
我们发现当

cur

走到

NULL

,遍历结束,链表完成反转。所以

cur==NULL

为循环结束条件。
代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */struct ListNode*reverseList(struct ListNode* head){struct ListNode* newHead =NULL;struct ListNode* cur = head;while(cur){struct ListNode* next = cur->next;
        cur->next = newHead;
        newHead = cur;
        cur = next;}return newHead;}

3. 链表的中间节点

在这里插入图片描述

  1. 奇数个数据:在这里插入图片描述
  2. 偶数个数据在这里插入图片描述 我们发现结束条件为fast为空或fast->next为空。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */struct ListNode*middleNode(struct ListNode* head){struct ListNode* slow,*fast;
    slow = fast = head;while(fast && fast->next){
        slow = slow->next;
        fast = fast->next->next;}return slow;}

4. 链表的倒数第k个节点

在这里插入图片描述

fast

先走

k

步,然后

fast

slow

同时走,当

fast

走到空,

slow

就是倒数第k个节点。

在这里插入图片描述
代码:

struct ListNode*FindKthToTail(struct ListNode* pListHead,int k ){struct ListNode* slow,*fast;
    slow = fast = pListHead;while(k--){if(fast ==NULL)returnNULL;
        fast = fast->next;}while(fast){
        slow = slow->next;
        fast = fast->next;}return slow;}

5.合并两个有序链表

在这里插入图片描述
每次取小的节点尾插到新链表。如果

list1

先走完,把剩下的

list2

直接尾插给

tail

,反之,剩下的

list1

尾插给

tail


在这里插入图片描述
特殊情况处理:当

list1

为空,返回

list2

,当

list2

为空,返回

list1

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */struct ListNode*mergeTwoLists(struct ListNode* list1,struct ListNode* list2){if(list1 ==NULL){return list2;}if(list2 ==NULL){return list1;}struct ListNode* head=NULL,*tail=NULL;while(list1 && list2){if(list1->val < list2->val){if(tail ==NULL){
                head = tail = list1;}else{
                tail->next = list1;
                tail = list1;}
            list1 = list1->next;}else{if(tail ==NULL){
                head = tail = list2;}else{
                tail->next = list2;
                tail = list2;}
            list2 = list2->next;}}if(list1){
        tail->next = list1;}if(list2){
        tail->next = list2;}return head;}

6. 链表分割

在这里插入图片描述

遍历原链表,把小于x的插入到一个链表1,把大于等于x的插入到一个链表2,链表1和链表2连接起来。
在这里插入图片描述
我们再考虑一下其他情况:
在这里插入图片描述
在这里插入图片描述
这种情况链表就成环了,此时程序死循环。只要把greattail->next== NULL就行了;
代码:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
    ListNode*partition(ListNode* pHead,int x){// write code herestruct ListNode*head1,*head2,*tail1,*tail2;
         head1=tail1=(struct ListNode*)malloc(sizeof(struct ListNode));
         head2=tail2=(struct ListNode*)malloc(sizeof(struct ListNode));
        tail1->next=NULL;
        tail2->next=NULL;struct ListNode* cur=pHead;while(cur){if(cur->val<x){
                tail1->next=cur;
                tail1=tail1->next;}else{
                tail2->next=cur;
                tail2=tail2->next;}
            cur=cur->next;}
    tail1->next=head2->next;
        tail2->next=NULL;//**必须要有,不然会在某些极端测试用例下会形成一个环,//那便 是死循环了,栈溢出。**
        pHead=head1->next;free(head1);free(head2);return pHead;}};

7.链表的回文结构

在这里插入图片描述
思路:先找到链表的中间节点,然后从中间节点开始把链表逆置,rHead,A同时走并比较。如果有不相等的,就说明不是回文,return false;如果有一个走完,return ture;
在这里插入图片描述
我们发现,偶数和奇数,这种方法都适用,因为即使把链表后半段逆置了,2也是指向3的。
代码:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/

class PalindromeList {
public:struct ListNode*middleNode(struct ListNode* head){struct ListNode* slow,*fast;
    slow = fast = head;while(fast && fast->next){
        slow = slow->next;
        fast = fast->next->next;}return slow;}struct ListNode*reverseList(struct ListNode* head){struct ListNode* newHead =NULL;struct ListNode* cur = head;while(cur){struct ListNode* next = cur->next;
        cur->next = newHead;
        newHead = cur;
        cur = next;}return newHead;}
    bool chkPalindrome(ListNode* A){struct ListNode *mid=middleNode(A);struct ListNode *rHead=reverseList(mid);while(A&&rHead){if(A->val!=rHead->val){return false;}else{ 
                A=A->next; 
                rHead=rHead->next;}}return true;}};

8.相交链表

在这里插入图片描述
思路:
在这里插入图片描述
代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */struct ListNode *getIntersectionNode(struct ListNode *headA,struct ListNode *headB){struct ListNode* tailA = headA,*tailB = headB;int lenA =1, lenB =1;while(tailA->next){
        tailA = tailA->next;++lenA;}while(tailB->next){
        tailB = tailB->next;++lenB;}if(tailA!=tailB){returnNULL;}struct ListNode* shortList = headA,*longList = headB;if(lenA > lenB){
        longList = headA;
        shortList = headB;}int gap =abs(lenA-lenB);while(gap--){
        longList = longList->next;}while(shortList && longList){if(shortList == longList){return shortList;}
        shortList = shortList->next;
        longList = longList->next;}returnNULL;}
标签: 数据结构 c语言

本文转载自: https://blog.csdn.net/iwkxi/article/details/123610179
版权归原作者 Yuucho 所有, 如有侵权,请联系我们删除。

“玩转链表,从这8道经典链表oj题开始”的评论:

还没有评论