zoukankan      html  css  js  c++  java
  • 线性表之单链表

    单链表的形式:

      单链表的每节点中除了数据域外,还包含一个指针域,用来指向下一个节点,主要有带头结点和不带头结点两种

      单链表定义如下:

    //单链表结构体定义
    typedef struct LNode {
        int data;
        struct LNode* next;
    }LNode;

    单链表中的两种基本算法:

    插入操作:

      .不妨设在节点A和节点B直间插入节点S,则具体分两步实现:

    •   节点S指向节点B,
    //让节点S指向B
    S->next = A->next;
    •   节点A指向S
    //节点A指S
    A->next = S

      注意,这两步的顺序不能弄反,否则会丢失数据;

    删除操作:

      同理,不妨设删除节点B,则只需要找到前一个节点A即可,具体实现如下:

    //p是要删除的节点
    p = A->next;
    A->next = A->next->next;
    //释放节点B的空间
    free(p);

    具体的相关算法实现:

    头插法建立单链表:

      插入的新节点在表头,旧的节点在新节点之后,不妨设已有头节点B,现插入节点A,则形式为A->B,关键代码如下所示:

      

    A->next = B->next;
    B->next=A;

      具体实现如下:

      

    //插入的节点在表头
    STATUS CreateListOfF(LNode *&P, int a[], int n) {
        //s用来指向新申请的节点
        LNode* s;
        int i;
        //申请P的头结点
        P =(LNode*) malloc(sizeof(LNode));
        P->next = NULL;
    
        for (i = 0; i < n; i++) {
            s = (LNode*)malloc(sizeof(LNode));
            s->data = a[i];
            //新节点指向旧节点
            s->next = P->next;
            //新节点称为新的开始节点
            P->next = s;
        }
    
        return OK;
    }

    尾插法建立单链表如下所示:

      关键在于新插入的节点在链表的尾部,不妨设最后插入的节点是F,则最后必须加上F->next = NULL,具体实现如下:

      

    //插入的节点在表尾
    STATUS CreateListOfR(LNode *&P, int a[], int n) {
        //s指向新申请的节点,r直线链表的终端节点
        LNode *s,*r;
        int i;
        //头结点的申请
        P = (LNode*)malloc(sizeof(LNode));
        P->next = NULL;
        r = P;
        for (i = 0; i < n; i++) {
            s = (LNode*)malloc(sizeof(LNode));
            s->data = a[i];
            
            //r指向终端节点
            r->next = s;
            r = s;
        }
        r->next = NULL;
        return OK;
    
    }

    打印链表元素:

    STATUS PrintList(LNode *P) {
        if (P->next == NULL) {
            return ERROR;
        }
    
        while (P->next != NULL) {
            cout << P->next->data << "	";
            P = P->next;
        }
        cout << endl;
        return OK;
    }

     查找某个元素并将其删除:

      删除元素两个关键点:

    • 待删除节点的查找;
    • 待删除节点的前驱节点;

      具体实现如下:

      

    STATUS FindAndDel(LNode *&P,int x) {
        //pre指向待删除节点的前一个节点
        LNode *pre, *p;
        p = P->next;
        pre = P;
        while (p != NULL) {
            if (p->data == x) {
                break;
            }
            pre = p;
            p = p->next;
        }
        
        //查找部分结束
        if (p == NULL) {
            return ERROR;
        }
        else {
            //让p前驱节点指向p后继节点
            pre->next = p->next;
            free(p);
            return OK;
        }
    
    
    }

    将两个有序递增链表A、B合并成一个递增有序链表C:

      递增有序链表在这使用尾插法,将两个有序的链表的元素一一比较,将较小的一个插入C中,依次递推。

      注意: A和B中的元素有可能一个已经完全插入,另外一个部分插入。不妨设A完全插入,B部分插入,这说明B的剩下元素完全大于B,这是只需要将B接入C即可;

      具体实现如下:

    STATUS MergeListRise(LNode *A, LNode *B, LNode *&C) {
        LNode *pA = A->next;
        LNode *pB = B->next;
        C = A;
      C->next = NULL;
    //r始终指向C节点 LNode *r; r = C; free(B); while (pA != NULL&&pB != NULL) { if (pA->data <= pB->data) { r->next = pA; r = pA;
           pA = pA->next; }
    else { r->next = pB; r = pB;
           pB = pB->next; } } r
    ->next = NULL; //处理有一部分插完而另外一部分未插完; if (pA != NULL) { r->next = pA; } if (pB->next != NULL) { r->next = pB; } return OK; }

    将两个有序递增链表A、B合并成一个递减有序链表C:

      同上述合并成一个递增有序链表类似,但这里使用头插法构建C,不需要r指针指向C的尾节点,具体实现如下:

      

    STATUS MergeListFall(LNode *A, LNode *B, LNode *&C) {
        LNode *pA = A->next;
        LNode *pB = B->next;
    
        C = A;
        C->next = NULL;
    
        free(B);
        //s指向待插入的节点
        LNode *s;
    
        while (pA!=NULL&&pB!=NULL)
        {
            if (pA->data <= pB->data) {
                //取得待插入节点s
                s = pA;
                pA = pA->next;
                s->next = C->next;
                C->next = s;
            }
            else
            {
                s = pB;
                pB = pB->next;
                s->next = C->next;
                C->next = s;
            }
        }
    
        //当某一个链表先处理完时
        while (pA != NULL)
        {
            s = pA;
            pA = pA->next;
            s->next = C->next;
            C->next = s;
    
        }
    
        while (pB != NULL)
        {
            s = pB;
            pB = pB->next;
            s->next = C->next;
            C->next = s;
    
        }
        return OK;
    }

      

  • 相关阅读:
    在知识爆炸的年代如何学习,避免成为PPT架构师
    同城双活的概念
    随笔《一个程序猿的生命周期》- 逆潮流而动的“叛逆者”
    连载《一个程序猿的生命周期》- 第1册《生存》篇全集 下载
    连载《一个程序猿的生命周期》- 44.感谢,我从事了IT相关的工作
    连载《一个程序猿的生命周期》- 43.我被这个时代淘汰了吗? ---2016年开篇,春节祝福!!!
    连载《一个程序猿的生命周期》- 42.新公司这一年,我都发生了哪些变化。--- 年底干货总结!!!
    连载《一个程序猿的生命周期》- 41.一个时代有一个时代人的使命
    【转载、推荐】不要自称是程序员,我十多年的 IT 职场总结
    [群友反馈] 程序猿身上的缺点
  • 原文地址:https://www.cnblogs.com/zuixime0515/p/9611522.html
Copyright © 2011-2022 走看看