• 常见的链表操作


    1. 链表的操作主要体现在对指针的操作,考察对指针的理解。
    2. 对链表的操作关键在于对链表的遍历,一种是常规正序遍历,另一种是逆序时采用的递归遍历。
    3. 链表复杂操作可能会需要多个指针协调工作。
    4. 注意考虑链表为空的情况。
    //链表定义
    typedef struct LNode{
        int data;
        struct LNode *next;
    }LNode,*LinkList;
    
    typedef struct LNode_C{
        char data;
        struct LNode_C *next;
    }LNode_C,*LinkList_C;
    
    typedef struct LNode_Dul{
        int data;
        struct LNode_Dul *next;
        struct LNode_Dul *prior;
        int freq;
    }LNode_Dul,*LinkList_Dul;

     

    一、链表的创建

    顺序生成一个有头结点单链表,元素类型为int
    //顺序生成一个有头结点单链表,元素类型为int
    void CreatList(LinkList *ptr_L)
    {
        *ptr_L = new LNode();
        (*ptr_L)->next = NULL;
        LinkList p = *ptr_L;
    
        int data;
        while (cin>>data)
        {
            LinkList temp_L = new LNode();
            temp_L->next = NULL;
            temp_L->data = data;
            p->next = temp_L;
            p = temp_L;
        }
    }
    逆序生成一个有头结点单链表,元素类型为int
    //逆序生成一个有头结点单链表,元素类型为int
    void CreatList_L(LinkList &L,int n){
        L=(LinkList)malloc(sizeof(LNode));
        L->next=NULL;
        cout<<"请从后到前输入链表内容:"<<endl;
        for (int i=n;i>0;i--)
        {
            LinkList p=(LinkList)malloc(sizeof(LNode));
            cin>>p->data;
            p->next=L->next;
            L->next=p;
        }
    }
    逆序生成一个有头结点单循环链表,元素类型为int
    //逆序生成一个有头结点单循环链表,元素类型为int
    void CreatList_L_Cir(LinkList &L,int n){
        L=(LinkList)malloc(sizeof(LNode));
        L->next=L;//最后元素指向L
        cout<<"请从后到前输入链表内容:"<<endl;
        for (int i=n;i>0;i--)
        {
            LinkList p=(LinkList)malloc(sizeof(LNode));
            cin>>p->data;
            p->next=L->next;
            L->next=p;
        }
    }
    逆序生成一个有头结点双循环链表,元素类型为int
    //逆序生成一个有头结点双循环链表,元素类型为int
    void CreatList_L_Cir_Dul(LinkList_Dul &L,int n){
        L=(LinkList_Dul)malloc(sizeof(LNode_Dul));
        L->next=L;//最后元素指向L
        cout<<"请从后到前输入链表内容:"<<endl;
        for (int i=n;i>0;i--)
        {
            LinkList_Dul p=(LinkList_Dul)malloc(sizeof(LNode_Dul));
            if(i==n) L->prior=p;
            p->freq=0;
            cin>>p->data;
    
            p->prior=L;//前驱
            L->next->prior=p;//前驱
    
            p->next=L->next;//后继
            L->next=p;//后继,此处L->暂存p以供下次循环使用
        }
    }
     二、单链表的操作
    链表反转
    //链表反转。先遍历,然后前方插入
    void InverseList(LinkList *L)
    {
        if ((*L) == NULL)
        {
            throw "error";
        }
    
        if ((*L)->next == NULL || (*L)->next->next ==NULL)
        {
            return;
        }
    
        LinkList pre = (*L)->next;
        LinkList p = (*L)->next->next;
    
        LinkList tmpFirst = (*L)->next;
    
        while(p)
        {
            LinkList tmp = p->next;
    
            (*L)->next = p;
            p->next = pre;
    
            pre = p;
            p = tmp;
        }
        tmpFirst->next = NULL; 
    }
    在带头结点的单链表结构上实现线性表操作,定位值为x的结点
    //在带头结点的单链表结构上实现线性表操作,定位值为x的结点
    int Locate(LinkList L,int x){
        int i=0;
        LinkList p=L;
        while(p&&p->data!=x){
            p=p->next;
            i++;
        }
        if (!p) return 0;
        return i;
    }
    在带头结点的单链表结构上实现线性表操作,求链表长度
    //在带头结点的单链表结构上实现线性表操作,求链表长度
    int ListLength_L(LinkList L){
        if (L == NULL)
        {
            throw "error";
        }
        int i=0;
        LinkList p=L->next;
        while (p){
        p=p->next;
        i++;
        }
        return i;
    }
    查找倒数第K个节点。
    //查找倒数第K个节点。设立双指针,先让第一个遍历到第k个节点,与此同时,第二个指针开始从头遍历,当第一个节点到尾部时,第二个节点即为倒数第k个节点
    LNode* FindNodeReverse(LinkList L, int k)
    {
        if (L == NULL || k == 0)
        {
            throw "error";
        }
    
        LinkList p = L->next;
        LinkList q = L->next;
        int i = 0;
        while(p && i < k)
        {
            i++;
            p = p->next;
        }
    
        if (i < k)
        {
            return NULL;
        }
        else
        {
            while(p)
            {
                p = p->next;
                q = q->next;
            }
            return q;
        }
    }
    查找单链表中间元素,即第(n/2+1)个结点。
    //查找单链表中间元素,即第(n/2+1)个结点。
    LNode* FindMiddleNode(LinkList L)
    {
        if (L == NULL)
        {
            throw "error";
        }
        if (L->next == NULL)
        {
            return NULL;
        }
    
        LinkList p1 = L;
        LinkList p2 = L;
        
        while(p1 && p2)
        {
            p1 = p1->next;
            p2 = p2->next;
            if (p2)
            {
                p2 = p2->next;
            }
        }
        return p1;
    }
    从尾到头打印单链表,使用栈
    // 从尾到头打印单链表,使用栈
    void VisitListReverse_Stack(LinkList L)
    {
        if (L == NULL)
        {
            throw "error";
        }
        stack<LNode> s;
        LinkList p = L;
        while(p)
        {
            s.push(*p);
            p = p->next;
        }
    
        while(!s.empty())
        {
            cout<<((s.top()).data)<<' ';
            s.pop();
        }
    }
    从尾到头打印单链表,递归
    // 从尾到头打印单链表,递归
    void VisitListReverse_Recur(LinkList L)
    {
        if (L == NULL) 
        {
            return;
        }
        else
        {
            VisitListReverse_Recur(L->next);
            cout<<L->data<<' ';
        }
    }
    判断一个单链表中是否有环。
    //判断一个单链表中是否有环。设立快慢指针,快指针一定在环内追赶上慢指针。
    bool HasCircle(LinkList L)
    {
        if (L == NULL)
        {
            throw "error";
        }
    
        LinkList p1 = L;
        LinkList p2 = L;
    
        while(p2->next != NULL && p2->next->next != NULL)
        {
            p1 = p1->next;
            p2 = p2->next->next;
    
            if (p1 == p2)
            {
                return true;
            }
        }
        return false;
    }
    已知一个单链表中存在环,求进入环中的第一个节点。
    //已知一个单链表中存在环,求进入环中的第一个节点。先判断是否存在环,找出相遇节点,然后将原链表转换为两个相交的链表,一个为从原头结点到相遇节点,另一个为从相遇节点的下一个节点到相遇节点
    LNode* FindFirstCircleNode(LinkList L)
    {
        if (L == NULL)
        {
            throw "error";
        }
    
        LinkList p1 = L;
        LinkList p2 = L;
    
        while(p2->next != NULL && p2->next->next != NULL)
        {
            p1 = p1->next;
            p2 = p2->next->next;
    
            //先判断是否存在环
            if (p1 == p2)
            {
                LinkList ptr_circle = p1->next;//新链表1的头结点
                int len_circle = 1;
                while(ptr_circle != p1)
                {
                    ptr_circle = ptr_circle->next;
                    len_circle++;
                }
    
                LinkList ptr_in = L;//新链表2的头结点
                int len_in = 1;
                while(ptr_in != p1)
                {
                    ptr_in = ptr_in->next;
                    len_in++;
                }
    
                //求取1、2两个链表的长度差值
                if (len_circle > len_in)
                {
                    int k = len_circle - len_in;
                    while (k--)
                    {
                        ptr_circle = ptr_circle->next;
                    }
                }
                else
                {
                    int k =len_in - len_circle;
                    while (k--)
                    {
                        ptr_in = ptr_in->next;
                    }
                }
    
                //求取第一个相遇节点
                while(ptr_circle != ptr_in)
                {
                    ptr_circle = ptr_circle->next;
                    ptr_in = ptr_in->next;
                }
                return ptr_circle;
            }
        }
        return NULL;
    }
    给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted。
    //给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted。将待删除节点的下一个节点的内容复制到待删除节点,然后删除待删除节点下一节点
    void Delete(LinkList pHead, LNode* pToBeDeleted)
    {
        if (pHead == NULL || pToBeDeleted == NULL || pHead == pToBeDeleted)
        {
            throw "error";
        }
        LinkList tmp = pToBeDeleted->next;
        if (tmp != NULL)
        {
            pToBeDeleted->data = pToBeDeleted->next->data;
            pToBeDeleted->next = pToBeDeleted->next->next;
            delete tmp;
        } 
        else//待删除节点为最后一个节点
        {
            tmp = pHead;
            while(tmp->next != NULL && tmp->next->next != NULL)
            {
                tmp = tmp->next;
            }
            tmp->next = NULL;
            delete pToBeDeleted;
        }
    }
    删除表中所有值大于mink且小于maxk的元素
    //已知线性表中的元素以值递增有序排列,并以单链表作存储结构。试写一高效的算法,删除表中所有值大于mink且小于maxk的元素(若表中存在这样的元素),同时释放被删结点空间,并分析你的算法的时间复杂度
    int ListDelete_L(LinkList &L,float mink, float maxk){
        if (mink>maxk) return -2;
        LinkList p=L->next, p_pre=L, q;
        while(p && p->data<maxk){
            if(p->data<=mink){
                p_pre=p;
                p=p->next;
            }
            else{
                q=p;
                p=p->next;
                free(q);
            }
        }
        p_pre->next=p;
        return 0;
    }
    删除表中所有值相同多余元素
    //已知线性表中的元素以值递增有序排列,并以单链表作存储结构。试写一高效的算法删除表中所有值相同多余元素。
    void ListDelete_LSameNode(LinkList &L){
        LinkList p=L, p_pre=L, q;
        p=p->next;
        while(p->next){
            p_pre=p;
            p=p->next;
            while(p && p_pre->data==p->data){//可能有多个和pre相同的元素,递增p
                p_pre->next=p->next;
                q=p;
                p=p->next;
                free(q);
            }
            if (!p) break;
        }
    }
    带freq域的双向循环链表上的查找
    //带freq域的双向循环链表上的查找
    LNode_Dul * Locate_DuList(LinkList_Dul &L,int x){
        LinkList_Dul p=L->next, q=NULL;
        while(p!=L && p->data!=x){
            p=p->next;
        }
        if(p==L) return NULL;
        ++(p->freq);
        q=p->prior;
        while(q!=L && q->freq<p->freq){
            q=q->prior;
        }
    
        //删除p
        p->prior->next=p->next;
        p->next->prior=p->prior;
    
        //插入p
        p->next=q->next;//先将用到q->next指针处理完
        q->next->prior=p;
    
        q->next=p;//然后改变q->next值
        p->prior=q;
    
        return p;
    }

     三、多链表操作

    判断两个单链表是否相交
    // 判断两个单链表是否相交
    bool Intersect(LinkList L1, LinkList L2)
    {
        if (L1 == NULL || L2 == NULL)
        {
            throw "error";
        }
    
        LinkList p1 = L1;
        while(p1->next != NULL)
        {
            p1 = p1->next;
        }
    
        LinkList p2 = L2;
        while(p2->next != NULL)
        {
            p2 = p2->next;
        }
    
        if (p1 == p2)
        {
            return true;
        }
        return false;
    }
    求两个单链表相交的第一个节点
    // 求两个单链表相交的第一个节点。先对齐两个链表的当前结点,使之到尾节点的距离相等
    LNode* FindFirsrtIntersect(LinkList L1, LinkList L2)
    {
        if (L1 == NULL || L2 == NULL)
        {
            throw "error";
        }
    
        LinkList p1 = L1;
        int len1 = 0;
        while(p1->next != NULL)
        {
            len1++;
            p1 = p1->next;
        }
        int len2 = 0;
        LinkList p2 = L2;
        while(p2->next != NULL)
        {
            len2++;
            p2 = p2->next;
        }
    
        //如果相交,则求相交节点
        if (p1 == p2)
        {
            if (len1 < len2)
            {
                int i = len2 - len1;
                p2 = L2;
                while(i--)
                {
                    p2 = p2->next;
                }
            }
            else
            {
                int i = len1 - len2;
                p1 = L1;
                while(i--)
                {
                    p1 = p1->next;
                }
            }
    
            while(p1 != p2)
            {
                p1 = p1->next;
                p2 = p2->next;
            }
            return p1;
        }
        return NULL;
    }
    已知两个单链表a 和b 各自有序,把它们合并成一个链表依然有序
    // 已知两个单链表a 和b 各自有序,把它们合并成一个链表依然有序
    void MergeSortedList(LinkList a,LinkList b,LinkList &c)
    {
        if (a == NULL && b == NULL)
        {
            throw "error";
            return;
        }
        else if (b != NULL && a == NULL)
        {
            c = b;
            return;
        }
        else if (a != NULL  && b == NULL)
        {
            c = a;
            return;
        }
        
        LinkList p1 = a;
        LinkList p2 = b;
        LinkList p = NULL; 
        if (p1->data != NULL && p2->data != NULL && p1->data > p2->data)
        {
            p = c = p2;
        }
        else
        {
            p = c = p1;
        }
    
        p1 = p1->next;
        p2 = p2->next;
    
        while(p1 && p2)
        {
            if (p1->data > p2->data)
            {
                p->next = p2;
                p = p2;
                p2 = p2->next;
            }
            else
            {
                p->next = p1;
                p = p1;
                p1 = p1->next;
            }
        }
    
        //连接未遍历的后续节点
        if (p1)
        {
            p->next = p1;
        }
        else
        {
            p->next = p2;
        }
    }

      

    已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序,递归
    // 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序,递归
    LNode* MergeSortedList_Recursive(LinkList pHead1,LinkList pHead2)
    {
        if(pHead1 == NULL)  
            return pHead2;  
        if(pHead2 == NULL)  
            return pHead1;  
        LinkList pHeadMerged = NULL;  
        if(pHead1->data < pHead2->data)  
        {  
            pHeadMerged = pHead1;  
            pHeadMerged->next = MergeSortedList_Recursive(pHead1->next, pHead2);  
        }  
        else  
        {  
            pHeadMerged = pHead2;  
            pHeadMerged->next = MergeSortedList_Recursive(pHead1, pHead2->next);  
        }  
        return pHeadMerged; 
    }
    假设有两个按元素值递增有序排列的线性表A和B,均以单链表作存储结构,请编写算法将A表和B表归并成一个按元素值递减有序(即非递增有序,允许表中含有值相同的元素)排列的线性表C,并要求利用原表(即A表和B表)的结点空间构造C表。
    //假设有两个按元素值递增有序排列的线性表A和B,均以单链表作存储结构,请编写算法将A表和B表归并成一个按元素值递减有序(即非递增有序,允许表中含有值相同的元素)排列的线性表C,并要求利用原表(即A表和B表)的结点空间构造C表。
    int ListMergeOppose_L(LinkList &A,LinkList &B,LinkList &C){
        LinkList pa=A->next, pb=B->next, pc_pre=NULL, pc, q;
        while(pa || pb){
            if (pa && (!pb || pa->data <= pb->data)){//注意if的条件
                pc=pa;
                q=pa->next;
                pa->next=pc_pre;
                pa=q;
            }
            else{
                pc=pb;
                q=pb->next;
                pb->next=pc_pre;
                pb=q;
            }
            pc_pre=pc;
        }
        C=A;A->next=pc;
        return 0;
    }
    求元素递增排列的线性表A和B的元素的交集并存入C中
    //求元素递增排列的线性表A和B的元素的交集并存入C中
    void LinkList_Intersect(LinkList A,LinkList B,LinkList &C){
        LinkList pa=A->next, pb=B->next, pc;
        C=pc=(LNode*)malloc(sizeof(LNode));
        while(pa && pb){
            if (pa->data<pb->data){
                pa=pa->next;            
            }
            else if(pa->data<pb->data){
                pb=pb->next;
            }
            else{
                LinkList pc1=(LNode*)malloc(sizeof(LNode));
                pc->next=pc1;
                pc1->data=pa->data;
                pc1->next=NULL;
                pc=pc1;
                pa=pa->next;
                pb=pb->next;
            }
        }
    }
    把单链表L的元素(char)按类型分为三个循环链表。
    //把单链表L的元素(char)按类型分为三个循环链表。A, B, C为带头结点的单循环链表类型。
    int LinkList_Divide(LinkList_C &L, LinkList_C &A, LinkList_C &B, LinkList_C &C){
        LinkList_C s=L->next, a, b, c;
        A=a=(LinkList_C)malloc(sizeof(LNode_C));
        B=b=(LinkList_C)malloc(sizeof(LNode_C));
        C=c=(LinkList_C)malloc(sizeof(LNode_C));
        while(s){
            if (isalpha(s->data))
            {
                a->next=s;
                a=a->next;
            }
            else if(isdigit(s->data)){
                b->next=s;
                b=b->next;
            }
            else{
                c->next=s;
                c=c->next;
            }
            s=s->next;
        }
        a->next=A;
        b->next=B;
        c->next=C;
        return 0;
    }
     
    所有函数都经过验证,如果大家发现有错误,欢迎留言,谢谢。
  • 相关阅读:
    C#中get和set的写法
    FineUI中Newtonsoft.Json版本报错解决办法
    ExtAspNet和FineUI未将对象引用设置到对象的实例
    【转载】写runat="server"有什么用
    (object sender,EventArgs e)是什么?
    【转载】onclick与onCommand的区别
    简单总结------redis
    将list等分成n份
    将List 分成n个长度由调用者指定的子List
    CountDownLatch 我的应用场景
  • 原文地址:https://www.cnblogs.com/wentfar/p/2705158.html
Copyright © 2020-2023  润新知