让你链表水平更上一层楼

链表

删除链表中等于给定值 val 的所有结点

在这里插入图片描述

1.创建一个哨兵位的头
2.将不是val的值链接进去
3.释放掉相同值的节点
4.记得尾部指针制空

struct ListNode* guard,*tail;
    tail=guard=(struct ListNode*)malloc(sizeof(struct ListNode));//哨兵位头节点
    guard->next=NULL;
    struct ListNode* cur=head;
    while(cur)
    {
        if(cur->val!=val)
        {
            tail->next=cur;
            tail=tail->next;
            cur=cur->next;
        }
        else
        {
            struct ListNode* next=cur->next;
            free(cur);
            cur=next;
        }
    }
    tail->next=NULL;
    struct ListNode* newnode=guard->next;//释放掉哨兵位的头
    free(guard);
    return newnode;
}

反转链表

在这里插入图片描述
两种方法:
1.用头插的方法将节点一个一个放入其中
2.直接倒置

     struct ListNode* cur=head;
     struct ListNode* rhead=NULL;
     while(cur)
     {
        struct ListNode* new=cur->next;//new里面存放下一个节点的地址
        cur->next=rhead;//先把第一个的next置为NULL 
        rhead=cur;//rhead换到当前节点的地址
        cur=new;//cur转换到new的地址
     }
     return rhead;//返回新的节点
 if(head==NULL)
        return NULL;//防止开始为空
   struct ListNode *n1,*n2,*n3;
    n1=NULL;
    n2=head;
    n3=n2->next;
    while(n2)
    {
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3!=NULL)
            n3=n3->next;
    }
    return n1;

链表的中间节点

方法:快慢指针

struct ListNode* middleNode(struct ListNode* head){
    //快慢指针
    if(head==NULL) 
    return NULL;
    struct ListNode* fastlist,*slowlist;
    fastlist=slowlist=head;
    while(fastlist&&fastlist->next)//如果是奇数个,那么fast后面一个为空;偶数个那么fast->next为空
    {
        fastlist=fastlist->next->next;
        slowlist=slowlist->next;
    }
    return slowlist;
}

链表中倒数第K个节点

方法:快慢指针,跳过K个节点就好

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    // write code here
    //快慢指针的应用
    if(pListHead==NULL)
        return NULL;
    struct ListNode* fast,*slow;
    fast=slow=pListHead;
    while(k--)//差几个节点,fast先走几步
    {
        if(fast)
            fast=fast->next;
        else//k可能会大于链表
            return NULL;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }   
    return slow;
}

合并两个有序链表

方法:哨兵位的头一大一小进行查找

        /创建哨兵位头节点
        struct ListNode* guard,*tail;
        struct ListNode* head;
        guard=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
        guard->next=NULL;
        //取小的尾插
        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;
        }
        head=guard->next;
        free(guard);
        return head;

链表分割

方法:哨兵位头+分割+整合

 //思想:把单链表尾 插变成大于和小于两个链表,再把大的链表尾插到小的链表后面
        ListNode* bighead,*bigtail,*smallhead,*smalltail;

        bighead=bigtail=(ListNode*)malloc(sizeof(ListNode));
        smallhead=smalltail=(ListNode*)malloc(sizeof(ListNode));
        
        bigtail->next=smalltail->next=NULL;



        ListNode* cur=pHead;
        while(cur)
        {
            if(cur->val<x)
            {
                smalltail->next=cur;
                smalltail=smalltail->next;
            }
            else 
            {
                bigtail->next=cur;
                bigtail=bigtail->next;
            }
            cur=cur->next;
        }
        smalltail->next=bighead->next;
        bigtail->next=NULL;//把大链接最后的指向改成NULL,否则会导致死循环。

        pHead=smallhead->next;

        free(bighead);
        free(smallhead);

        return pHead;
    }

链表的回文

方法:先快慢找到回文的中间节点+后半段逆置+比较
注意:如果数量是奇数,回文后刚好前面是n/2-1个,后面是n/2+1,但是少的一节的最后一个刚好是指向多的一个的最后一个

class PalindromeList {
    //快慢指针
 ListNode*  Mid(ListNode* head)
    {
        ListNode* fast,*slow;  
        fast=slow=head;
        while(fast&&fast->next)
        {
            fast=fast->next->next;
            slow=slow->next;
        }
        return slow;
    }
    //逆置
    ListNode* Reser(ListNode* head)
    {
        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;
    }

public:
    bool chkPalindrome(ListNode* A) {
        //快慢指针找中间+逆置后半段+比较
        // write code here
        ListNode* mid=Mid(A);
        ListNode* rhead=Reser(mid);
        while(A&&rhead)
        {
            if(A->val!=rhead->val)
                return false;
            A=A->next;
            rhead=rhead->next;
        }
        return true;
    }

环形链表

方法:快慢指针
思路:追击问题,如果慢的比快的少走一步,那如果是环形,肯定能追上,因为即使套圈,那么只差一个,会在相同位置遇到

bool hasCycle(struct ListNode *head) {
    //追击问题,快慢指针
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow) 
            return true;
    }
    return false;
}

环形链表进阶版

方法:找到相遇位置,快指针从相遇位置先走,慢指针从出发位置走,碰到的第一个节点就是要找的节点
原因:
设直线为L,相遇的点到要找的节点距离为N,一圈为长度为C
在这里插入图片描述

相交问题

方法:看长短差多少,让长的先走差值,然后两者同时走,如果相交那么就可以碰到,如果不行就是没相交

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
    //把两个链表搞成相等的,让他一一对照
    struct ListNode* s1=headA,*s2=headB;
    int A=0,B=0;
    //找出两个链表差多少
    while(s1->next)
    {
        A++;
        s1=s1->next;
    }
    while(s2->next)
    {
        B++;
        s2=s2->next;
    }
    //不相交就输出错误
    if(s1!=s2)
    {
        return NULL;
    }//相交
        int gde=abs(A-B);
        struct ListNode* longside=headA;
        struct ListNode* shortside=headB;
        if(B>A)//谁更长就把长的付给谁
        {
            longside=headB;
            shortside=headA;
        }
        //长的先走
        while(gde--)
        {
            longside=longside->next;
        }
        //同时走。找交点
        while(longside!=shortside)
        {
            longside=longside->next;
            shortside=shortside->next;
        }
        return longside;
}

复制带随机指针的链表

方法:先把节点一一对照挂到原链表上,把random对应上去,拆下来尾插

	//1.挂上源节点
    struct Node* cur= head;
    while(cur)
    {
        struct Node* next = cur->next;

        struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;

        copy->next=next;
        cur->next=copy;

        cur=next;
    }
    //2.查找random
    cur = head;
    while(cur)
    {
        struct Node* copy= cur->next;

        if(cur->random == NULL)//万一有节点指向空,那么需要把copy也指向空
        {
            copy->random = NULL;
        }
        else
        {
            copy->random = cur->random->next;
        }
        cur=cur->next->next;
    }
    //3.取下尾插
    cur=head;
    struct Node* rhead,*tail;
    rhead=tail=NULL;
    
    while(cur)
    {
        struct Node* copy=cur->next;
        struct Node* next=copy->next;

        cur->next = next;
        if(tail==NULL)
        {
            rhead=tail=copy;
            //cur->next=copy->next;
        }
        else
        {
            tail->next=copy;
            tail=tail->next;
        }
        cur=next;
    }
    return rhead;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青青丘比特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值