• 双向链表 C语言 (创建,插入,删除,判空,返回链表长度)


    嘿,(≧▽≦)/ 前几天在书上看见了双向链表,就学了一下,哈哈哈(〜^㉨^)〜

    顾名思义,双向链表每个结点有两个指针域,一个指向前驱节点,一个指向后继结点。

    但是双向链表在创建,插入,和删除操作上略有不同。例如在插入和删除时,不必像单链表一样只能在目标的前驱结点上操作

    (觉得它能实现查询数据时上一个,下一个的功能哦!!)



    下面只是我的一些想法,可能很菜啊    ╮( ̄▽ ̄")╭;


    结点定义如下:

    typedef struct Node
    {
        int data;
        struct Node *prior;  //指向前驱
        struct Node *next;   //指向后继
    }Node,*pNode;    //这里 pNode 等价于 Node* 是指向结点的指针

    函数声明如下:

    pNode creat(int n);        //创建双向链表
    void output(pNode h);    //打印双向链表
    int if_empty(pNode);     //判空
    int length(pNode h);      //返回链表长度
    void Insert(pNode h,int i,int data);     //插入
    void Delete(pNode h,int i);    //删除
    


    各项功能的函数定义如下:

    (1)创建双链表

    pNode creat(int n)  //创建链表
    {
        int i;
        pNode h,p,r;
        h=r=(pNode)malloc(sizeof(Node));//其中h是头指针,r是尾指针
        if(h==NULL)    //内存分配失败
            exit(-1);
        h->prior=h->next=NULL;  //将头节点的两个指针域都指向NULL
        printf("输入数据:");
        for(i=0; i<n; i++)
        {
            p=(pNode)malloc(sizeof(Node));
            if(h==NULL)      //内存分配失败
                exit(-1);
            scanf("%d",&p->data);
            p->next=NULL;
            r->next=p;
            p->prior=r;
            r=r->next;
        }
        return h;
    }
    

      双向链表的创建我采用的是尾插法,因为如果是头插法则会有两种情况,1是在头结点和NULL之间插,2是在头结点与其后结点之间插,稍微麻烦一点点。而尾插法只需插在尾结点和NULL之间。在文章最后我附上了双向链表的头插法。


    (2)打印链表,判空,返回链表长度

    void output(pNode h)   //打印链表
    {
        pNode p=h->next;
        printf("打印链表:");
        while(p)
        {
            printf("%d ",p->data);
            p=p->next;
        }
    }
    
    int empty(pNode h)    //判断链表是否为空
    {
        pNode p=h->next;
        if(p==NULL)
            return 1;
        else
            return 0;
    }
    
    int length(pNode h)    //返回链表长度
    {
        int length=0;
        pNode p=h->next;
        while(p)
        {
            length++;
            p=p->next;
        }
        return length;
    }
    
    


    (3)插入操作

    void Insert(pNode h,int i,int data) //插入 1<=i<=length+1
    {
        pNode p,r;
        p=r=h;
        int j=0;
        if(i==length(h)+1) //当插入的位置为length+1时
        {
            pNode q=(pNode)malloc(sizeof(Node));
            q->data=data;
            q->next=NULL;
            while(r->next) //找到链表尾结点
                r=r->next;
            r->next=q;
            q->prior=r;
        }
        else
        {
            while(p&&(j<i))  //找到第i个结点的
            {
                p=p->next;
                j++;
            }
            if(!p||(j>i)) 
                exit(-1);
            pNode q=(pNode)malloc(sizeof(Node));
            q->data=data;
            //插入的核心步骤
            q->prior=p->prior;
            p->prior->next=q;
            q->next=p;
            p->prior=q;
            //
        }
    }
    
      1.插入有两种情况,一是在两结点之间,另外一个是最后一个节点与NULL之间。

      2.对于两节点之间插入的情况,指针p指向了其中一个节点,则新结点先与另一个结点连接,之后再与该结点连接。因为指针p已经记录了该结点的位置,不用担心指向它的指针域被覆盖。

    (3)删除操作

    void Delete(pNode h,int i)  //删除
    {
        pNode p=h;
        int j=0;
        while(p&&(j<i))  //找到删除结点
        {
            p=p->next;
            j++;
    
        }
        if(p->next==NULL)
            p->prior->next=NULL;
        else
        {
            p->prior->next=p->next;
            p->next->prior=p->prior;
        }
        free(p);
    }

      删除操作有p->next==NULL和p->next!=NULL两种情况


    用于测试的主函数

    int main()
    {
        int n,i,data;
        pNode head;
        printf("输入输入数据个数");
        scanf("%d",&n);
        head=creat(n);
        output(head);
        printf("
    输入插入 位置i 和 数据data :
    ");
        scanf("%d",&i);
        scanf("%d",&data);
        Insert(head,i,data);
        output(head);
    
    
        printf("
    要删除第几个数据");
        scanf("%d",&i);
        Delete(head,i);
        output(head);
        return 0;
    }


    (≧▽≦)/(≧▽≦)/(≧▽≦)/(≧▽≦)/(≧▽≦)/(≧▽≦)/~~~~~~先结束了。




    附录

    双向链表的头插法

    pNode creat(int n)
    {
        int i;
        pNode h,p;
        h=(pNode)malloc(sizeof(Node));
        if(h==NULL)
            exit(-1);
        h->prior=h->next=NULL;
        printf("输入数据:");
        p=(pNode)malloc(sizeof(Node));
        if(h==NULL)
            exit(-1);
        scanf("%d",&p->data);
        h->next=p;
        p->prior=h;
        p->next=NULL;
        for(i=1; i<n; i++)
        {
            p=(pNode)malloc(sizeof(Node));
            if(h==NULL)
                exit(-1);
            scanf("%d",&p->data);
            p->next=h->next;
            h->next->prior=p;
            h->next=p;
            p->prior=h;
        }
        return h;
    }
    



  • 相关阅读:
    PHPStorm--美化
    Laravel5.1 模型--关联关系(复杂)
    HTML5 getUserMedia/AudioContext 打造音谱图形化
    如何在终端实时展现当前运行的git分支
    关于ionic的跨域问题
    ionic插件安装与卸载
    虚拟机调试ionic项目
    ionic双击退出键退出APP
    npm install 镜像
    对Date的扩展,将 Date 转化为指定格式的String
  • 原文地址:https://www.cnblogs.com/zhanyeye/p/9746132.html
Copyright © 2020-2023  润新知