数据结构——双向链表

双向链表的结构:

双向链表由链表对象,头结点,中间结点以及尾结点组成每一部分结点结构或是指针内容存在差异,需要牢记双向链表的结构,双向链表的结构使我们能够通过一个中间节点找到它前后的结点,这是与单向链表的最大区别。

需要熟练掌握的基本操作:

让我们在记牢理解双向链表的结构以后直接上代码练习

封装双向链表:1:头文件定义双向链表的结构

复制代码
#ifndef __DOULINK_H__
#define __DOULINK_H__
//双向链表存储的数据类型
typedef struct stu
{
    int id;
    char name[32];
    int score;
}Data_type_t;

/*双向链表的结点类型*/
typedef struct dounode
{
    Data_type_t data;
    struct dounode *ppre;  //指向前驱结点的指针
    struct dounode *pnext; //指向后继结点的指针
}DNode_t;

/*双向链表对象类型*/
typedef struct doulink
{
    DNode_t *phead;   //双向链表头结点地址
    int clen;         //双向链表结点个数
}DLink_t;
extern DLink_t *create_doulink();
extern int insert_doulink_head(DLink_t *pdlink, Data_type_t data);
extern int is_empty_doulink(DLink_t *pdlink);
extern void doulink_for_each(DLink_t *pdlink, int dir);
extern int insert_doulink_tail(DLink_t *pdlink, Data_type_t data);
extern int delete_doulink_head(DLink_t *pdlink);
extern int delete_doulink_tail(DLink_t *pdlink);

使用头插法构建双向链表:头插法是重点

复制代码
#include "doulink.h"
#include <stdio.h>
#include <stdlib.h>


DLink_t *create_doulink()
{
    DLink_t *pdlink= malloc(sizeof(DLink_t));
    if (NULL == pdlink)
    {
        printf("malloc error");
        return NULL;
    }
    pdlink->phead = NULL;
    pdlink->clen = 0;

    return pdlink;
}

int is_empty_doulink(DLink_t *pdlink)
{
    return NULL == pdlink->phead;

}


int insert_doulink_head(DLink_t *pdlink, Data_type_t data)
{
    DNode_t *pnode = malloc(sizeof(DNode_t));
    if (NULL == pnode)
    {
        printf("malloc error");
        return -1;
    }
    pnode->data = data;
    pnode->ppre = NULL;
    pnode->pnext = NULL;

    if (is_empty_doulink(pdlink))
    {
        pdlink->phead = pnode;
    }
    else
    {
        pnode->pnext = pdlink->phead;
        pdlink->phead->ppre = pnode;
        pdlink->phead = pnode;
    }
    pdlink->clen++;

    return 0;
}

主函数部分:

复制代码
#include <stdio.h>
#include "doulink.h"

int main(void)
{

    Data_type_t stus[5] = {{1, "zhangsan", 99},
                            {2, "lisi", 100}, {3, "wangwu", 90}, 
                            {4, "maliu", 56}, {5, "tianqi", 66}};

    DLink_t *pdlink = create_doulink();
    if (NULL == pdlink)
    {
        return -1;
    }

    insert_doulink_head(pdlink, stus[0]);
    insert_doulink_head(pdlink, stus[1]);
    insert_doulink_head(pdlink, stus[2]);
    insert_doulink_tail(pdlink, stus[3]);
    insert_doulink_tail(pdlink, stus[4]);

构建好双向链表后,对于双向链表的各种基本操作:

遍历打印:dir1顺序打印,direlse逆序打印

复制代码
void doulink_for_each(DLink_t *pdlink, int dir)
{
    if (is_empty_doulink(pdlink))
    {
        return ;
    }
    DNode_t *ptmp = pdlink->phead;
    if (dir)
    {
        while (ptmp != NULL)
        {
            printf("%d %s %d\n", ptmp->data.id, ptmp->data.name, ptmp->data.score);
            ptmp = ptmp->pnext;
        }
    }
    else
    {
        while (ptmp->pnext != NULL)
        {
            ptmp = ptmp->pnext;
        }
        while (ptmp != NULL)
        {
             printf("%d %s %d\n", ptmp->data.id, ptmp->data.name, ptmp->data.score);
             ptmp = ptmp->ppre;
        }
    }
    printf("\n");
}

尾插法

复制代码
int insert_doulink_tail(DLink_t *pdlink, Data_type_t data)
{
    DNode_t *pnode = malloc(sizeof(DNode_t));
    if (NULL == pnode)
    {
        printf("malloc error\n");
        return -1;
    }
    pnode->data = data;
    pnode->ppre = NULL;
    pnode->pnext = NULL;

    if (is_empty_doulink(pdlink)) //空链表情况
    {
        pdlink->phead = pnode;
    }
    else //非空链表情况
    {
        DNode_t *ptmp = pdlink->phead;
        while (ptmp->pnext != NULL)
        {
            ptmp = ptmp->pnext;
        }
        ptmp->pnext = pnode;
        pnode->ppre = ptmp;
    }
    pdlink->clen++;

    return 0;
}

删除头结点:

复制代码
int delete_doulink_head(DLink_t *pdlink)
{
    if (is_empty_doulink(pdlink))
    {
        return -1;
    }

    DNode_t *pdel = pdlink->phead;
    pdlink->phead = pdel->pnext;
    if (pdlink->phead != NULL)
    {
        pdlink->phead->ppre = NULL;
    }
    free(pdel);
    pdlink->clen--;

    return 0;
}

删除尾结点:

复制代码
int delete_doulink_tail(DLink_t *pdlink)
{
    if (is_empty_doulink(pdlink))
    {
        return -1;
    }

    DNode_t *ptmp = pdlink->phead;
    if (1 == pdlink->clen)
    {
        free(ptmp);
        pdlink->phead = NULL;
    }
    else
    {
        while (ptmp->pnext != NULL)
        {
            ptmp = ptmp->pnext;
        }
        ptmp->ppre->pnext = NULL;
        free(ptmp);
    }
    pdlink->clen--;

    return 0;
}

销毁链表

复制代码
int destory_dblink(dbLINK_T *plink)
{
    if(is_empty_doubleLink(plink))
    {
        printf("空结点");
        return -1;
    }

    dbNODE_T *p=plink->phead;
    while(p!=NULL)
    {
        p=p->pnext;
        head_node_delet(plink);
        
    }
    free(plink);
    return 0;
    

}

== 这个销毁方法无法销毁主函数里面创造的plink==,,这时我们使用二级指针销毁主函数以及封装函数里的双向链表

查找结点并返回其地址

复制代码
dbNODE_T *findnode(dbLINK_T *plink,char name[20])
{
    if(is_empty_doubleLink(plink))
    {
        printf("空链表,无结点可查");
        return NULL;
    }
    dbNODE_T *p=plink->phead;
    while (p!=NULL)
    {
        if(strcmp(p->data.name,name)==0)
        {
            return p;
        }
        p=p->pnext;
    }
    printf("查找不到该学生");    
    return NULL;
}

根据名字修改学生分数

复制代码
int findnodeAndChangeScore(dbLINK_T *plink,char name[20],int newscore)
{
    if(is_empty_doubleLink(plink))
    {
        printf("空链表,无结点可查");
        return -1;
    }
    dbNODE_T *p=plink->phead;
    while (p!=NULL)
    {
        if(strcmp(p->data.name,name)==0)
        {
            p->data.score=newscore;
            return 0;
        }
        p=p->pnext;
    }
    printf("查找不到该学生");    
    return -1;
}

查找结点并删除该结点:

复制代码
int findnodeAndDELETnode(dbLINK_T *plink, char name[20])
{
    if(is_empty_doubleLink(plink))
    {
        printf("空链表,无结点可查\n");
        return -1;
    }
    
    dbNODE_T *p = plink->phead;
    
    // 遍历整个链表查找节点
    while (p != NULL)
    {
        if(strcmp(p->data.name, name) == 0)
        {
            // 情况1:删除头节点
            if(p->ppre == NULL)
            {
                head_node_delet(plink);
            }
            // 情况2:删除尾节点
            else if(p->pnext == NULL)
            {
                p->ppre->pnext = NULL;
                free(p);
                plink->clen--;
            }
            // 情况3:删除中间节点
            else
            {
                p->ppre->pnext = p->pnext;
                p->pnext->ppre = p->ppre;
                free(p);
                plink->clen--;
            }
            printf("找到并删除该学生节点\n");
            return 0;
        }
        p = p->pnext;
    }
    
    // 遍历完未找到节点
    printf("无法找到该同学,无法删除结点\n");
    return -1;
}

主函数

复制代码
#include<stdio.h>
#include"doublelink.h"
int main(void)
{
    STUDENT_T stus[5]={{1,"zhangsan",99}
    ,{2,"lisi",100}
    ,{3,"wangwu",90}
    ,{4,"maliu",56}
    ,{5,"tianqi",66}};
    dbLINK_T *plink=creatlink(plink);
    if(plink==NULL)
    {
        printf("mallol error");
        return -1;
    }
    creat_db_NODE(plink,stus[0]);
    creat_db_NODE(plink,stus[1]);
    creat_db_NODE(plink,stus[2]);
    creat_db_NODE(plink,stus[3]);
    creat_db_NODE(plink,stus[4]);
  /*  insert_dblink_tail(plink,stus[4]);
    leach_dblink(plink,1);
    head_node_delet(plink);
    deletLink_fromTheLastNODE(plink);*/
    leach_dblink(plink,1);
  /*  dbNODE_T *ret=findnode(plink,"wangwu");
    if(ret==NULL)
    {
        return -1;
    }
    printf("学生名:%p\n",ret);*/
  /*  findnodeAndChangeScore(plink,"lisi",50);
    leach_dblink(plink,1);*/
    findnodeAndDELETnode(plink,"wangwu");
    leach_dblink(plink,1);
    destory_dblink(plink);
  //  leach_dblink(plink,0);
    return 0;
}
相关推荐
2501_924879361 分钟前
口罩识别场景误报率↓79%:陌讯多模态融合算法实战解析
人工智能·深度学习·算法·目标检测·智慧城市
Christo335 分钟前
TFS-2022《A Novel Data-Driven Approach to Autonomous Fuzzy Clustering》
人工智能·算法·机器学习·支持向量机·tfs
木木子999939 分钟前
超平面(Hyperplane)是什么?
算法·机器学习·支持向量机·超平面·hyperplane
星空下的曙光2 小时前
React 虚拟 DOM Diff 算法详解,Vue、Snabbdom 与 React 算法对比
vue.js·算法·react.js
大阳1232 小时前
数据结构2.(双向链表,循环链表及内核链表)
c语言·开发语言·数据结构·学习·算法·链表·嵌入式
掘根2 小时前
【Redis】string字符串
数据结构·数据库·redis
CUC-MenG3 小时前
2025牛客多校第六场 D.漂亮矩阵 K.最大gcd C.栈 L.最小括号串 个人题解
c语言·c++·算法·矩阵
2401_876221344 小时前
Tasks and Deadlines(Sorting and Searching)
c++·算法
jie*4 小时前
小杰数据结构——题库——拂衣便欲沧海去,但许明月随吾身
数据结构·windows·python