IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 王道数据结构实践代码----双链表的实现(C语言版) -> 正文阅读

[数据结构与算法]王道数据结构实践代码----双链表的实现(C语言版)

王道数据结构实践代码----单链表的实现(C语言版)

前言

日期:2021年8月28日
书籍:王道2021年数据结构考研复习指导
代码内容:实现双链表的实现,包括初始化,插入新元素,删除新元素,输出,查询

代码难点

1.双链表插入、删除的操作

在这里插入图片描述
上图操作的语句顺序不是唯一的,但也不是任意的,①和②两步必须在④步之前,否则p的后继结点的指针就会丢掉,导致插入失败。
为了加深理解,读者可以在纸上画出示意图。
若问题改成要求在结点
p之前插入结点s,请读者思考具体的操作步骤。
在这里插入图片描述
此处①②无顺序要求
若问题改成要求删除结点
q的前驱结点*p,请读者思考具体的操作步骤。

代码展示

双链表结构体定义

#include <stdio.h>
#include <stdlib.h>

//C语言自定义bool操作
#define bool char
#define false 0
#define true 1

/*数据元素类型*/
typedef int ElemType;

/*双链表结构体定义*/
typedef struct DNode        //定双链表结点类型
{
    ElemType data;          //每个结点存放一个数据元素
    struct DNode *next;     //指针指向下一节点
    struct DNode *prior;    //指针指向上一节点
}DNode,*DLinkList;

双链表初始化函数

/*双链表初始化函数*/
DLinkList DLinkListInit()
{
    //[1]申请空间
    DLinkList L = (DLinkList)malloc(sizeof(DLinkList));
    //[2]安排指针
    L->next = NULL;
    L->prior = NULL;
    //[3]返回头节点
    return L;
}

双链表的插入操作

/*双链表的插入操作*/
//【1】双链表新节点的创建,返回新节点指针
DNode* CreateNewDNode(ElemType data)
{
    //[1]为新节点分配空间,并判断是否分配成功
    DNode* newNode = (DNode*)malloc(sizeof(DNode));
    if(!newNode)
    {
        printf("分配空间失败,请检查内存!\n");
        return NULL;
    }
    //[2]初始化新节点
    newNode->data = data;
    newNode->next = NULL;
    newNode->prior = NULL;
    //[3]返回节点地址
    return newNode;
}
//【2】双链表节点定位----按位序号查询,返回需要查找的节点的指针
DNode* GetElem(DLinkList L, int i)
{
    //[1]判空
    if(L->next == NULL) {printf("这是空表!"); return L;}
    //[2]生成指向目标节点的指针p
    DNode* p = L->next;
    //[3]如果i = 0
    if(i < 1)
    {
        p = L;
        return p;
    }
    //[4]开始循环定位
    while (p->next != NULL && i != 1)
    {
        p = p->next;
        i--;
    }
    //[5]返回节点
    if(i != 1)
    printf("没有这个节点,返回链表的最后一位.\n");
    return p;
}
//【3】双链表节点定位----按内容值查询,返回需要查找的节点的指针
DNode* LocateElem(DLinkList L,ElemType e)
{
    //[1]判空
    if(L->next == NULL) {printf("这是空表!"); return L;}
    //[2]生成指向目标节点的指针p
    DNode* p = L->next;
    //[3]开始循环定位
    while (p->next != NULL && p->data != e)
    {
        p = p->next;
    }
    //[4]返回节点
    if(p->data != e)//排除最后一位元素是目标元素的情况
    printf("没有这个节点,返回链表的最后一位.");
    return p;
}
//【4】双链表的插入操作
//在第i位插入新元素,如果第i位不存在,则插入在表尾
bool DLinkListInsert(DLinkList L,int i,ElemType e)
{
    //[0]程序健壮性增强
    if(i < 1)
    {
        printf("输入出错!");
        return 0;
    }
    //[1]建立新元素节点
    DNode* s = CreateNewDNode(e);
    if(s == NULL) return 0;
    //[2]生成指向待插入位置的指针p
    DNode* p = GetElem(L,i-1);
    //[3]插入新节点
    s->next = p->next;
    if(p->next != NULL)
        p->next->prior = s;
    s->prior = p;
    p->next = s;
    //[4]插入成功,返回结果
    return 1;
}

双链表的遍历

/*双链表的遍历*/
int PrintDLinkList(DLinkList L)
{
    //[1]判空
    if (L == NULL)
    {
        printf("该链表不存在\n");
        return 0;
    }
    
    if(L->next == NULL)
    {
        printf("这是空表!没有需要打印的元素");   
        return 0;
    }
    //[2]生成当前要打印的元素位置的指针p
    DNode* p = L->next;
    //[3]遍历打印
    int i = 0;
    while (p!= NULL)
    {
        i++;
        printf("第%d个元素的内容值为:%d\n",i,p->data);
        p = p->next;
        
    }
    printf("打印结束,共%d个链表结点.\n",i);
    return 0;
}

双链表的删除操作

//按位删除
bool DLinkLisDelete(DLinkList L,int i)
{
    //[1]判空
    if(L->next == NULL)
    {
        printf("表空,无删除元素\n");
        return false;
    }
    //[2]定位,找到待删除元素的前一位*p和待删除元素*q
    DNode* p = GetElem(L,i-1);
    if(p == NULL) return false;
    DNode* q = p->next;
    if(q == NULL) return false; //*p没有后继结点
    //[3]执行删除操作
    p->next = q->next;
    if(q->next != NULL)         //*q不是最后一位元素
        q->next->prior = p;
    free(q);
    return true;
    //没有q的写法
    // if(p->next == NULL) false;  //最后一位,没有后继
    // p->next = p->next->next;
    // if(p->next->next != NULL)   //待删除结点不是最后一个节点
    //     p->next->next->prior = p;
    // free(p);              //释放结点空间
    // return true;
}
//删除双链表
void DestoryList(DLinkList L)
{
    while (L->next != NULL)
    {
        DLinkLisDelete(L,1);
    }
}

整体代码展示

#include <stdio.h>
#include <stdlib.h>

//C语言自定义bool操作
#define bool char
#define false 0
#define true 1

/*数据元素类型*/
typedef int ElemType;

/*双链表结构体定义*/
typedef struct DNode        //定双链表结点类型
{
    ElemType data;          //每个结点存放一个数据元素
    struct DNode *next;     //指针指向下一节点
    struct DNode *prior;    //指针指向上一节点
}DNode,*DLinkList;

/*双链表初始化函数*/
DLinkList DLinkListInit()
{
    //[1]申请空间
    DLinkList L = (DLinkList)malloc(sizeof(DLinkList));
    //[2]安排指针
    L->next = NULL;
    L->prior = NULL;
    //[3]返回头节点
    return L;
}

/*双链表的插入操作*/
//【1】双链表新节点的创建,返回新节点指针
DNode* CreateNewDNode(ElemType data)
{
    //[1]为新节点分配空间,并判断是否分配成功
    DNode* newNode = (DNode*)malloc(sizeof(DNode));
    if(!newNode)
    {
        printf("分配空间失败,请检查内存!\n");
        return NULL;
    }
    //[2]初始化新节点
    newNode->data = data;
    newNode->next = NULL;
    newNode->prior = NULL;
    //[3]返回节点地址
    return newNode;
}
//【2】双链表节点定位----按位序号查询,返回需要查找的节点的指针
DNode* GetElem(DLinkList L, int i)
{
    //[1]判空
    if(L->next == NULL) {printf("这是空表!"); return L;}
    //[2]生成指向目标节点的指针p
    DNode* p = L->next;
    //[3]如果i = 0
    if(i < 1)
    {
        p = L;
        return p;
    }
    //[4]开始循环定位
    while (p->next != NULL && i != 1)
    {
        p = p->next;
        i--;
    }
    //[5]返回节点
    if(i != 1)
    printf("没有这个节点,返回链表的最后一位.\n");
    return p;
}
//【3】双链表节点定位----按内容值查询,返回需要查找的节点的指针
DNode* LocateElem(DLinkList L,ElemType e)
{
    //[1]判空
    if(L->next == NULL) {printf("这是空表!"); return L;}
    //[2]生成指向目标节点的指针p
    DNode* p = L->next;
    //[3]开始循环定位
    while (p->next != NULL && p->data != e)
    {
        p = p->next;
    }
    //[4]返回节点
    if(p->data != e)//排除最后一位元素是目标元素的情况
    printf("没有这个节点,返回链表的最后一位.");
    return p;
}
//【4】双链表的插入操作
//在第i位插入新元素,如果第i位不存在,则插入在表尾
bool DLinkListInsert(DLinkList L,int i,ElemType e)
{
    //[0]程序健壮性增强
    if(i < 1)
    {
        printf("输入出错!");
        return 0;
    }
    //[1]建立新元素节点
    DNode* s = CreateNewDNode(e);
    if(s == NULL) return 0;
    //[2]生成指向待插入位置的指针p
    DNode* p = GetElem(L,i-1);
    //[3]插入新节点
    s->next = p->next;
    if(p->next != NULL)
        p->next->prior = s;
    s->prior = p;
    p->next = s;
    //[4]插入成功,返回结果
    return 1;
}

/*双链表的遍历*/
int PrintDLinkList(DLinkList L)
{
    //[1]判空
    if (L == NULL)
    {
        printf("该链表不存在\n");
        return 0;
    }
    
    if(L->next == NULL)
    {
        printf("这是空表!没有需要打印的元素");   
        return 0;
    }
    //[2]生成当前要打印的元素位置的指针p
    DNode* p = L->next;
    //[3]遍历打印
    int i = 0;
    while (p!= NULL)
    {
        i++;
        printf("第%d个元素的内容值为:%d\n",i,p->data);
        p = p->next;
        
    }
    printf("打印结束,共%d个链表结点.\n",i);
    return 0;
}

/*双链表的删除操作*/
//按位删除
bool DLinkLisDelete(DLinkList L,int i)
{
    //[1]判空
    if(L->next == NULL)
    {
        printf("表空,无删除元素\n");
        return false;
    }
    //[2]定位,找到待删除元素的前一位*p和待删除元素*q
    DNode* p = GetElem(L,i-1);
    if(p == NULL) return false;
    DNode* q = p->next;
    if(q == NULL) return false; //*p没有后继结点
    //[3]执行删除操作
    p->next = q->next;
    if(q->next != NULL)         //*q不是最后一位元素
        q->next->prior = p;
    free(q);
    return true;
    //没有q的写法
    // if(p->next == NULL) false;  //最后一位,没有后继
    // p->next = p->next->next;
    // if(p->next->next != NULL)   //待删除结点不是最后一个节点
    //     p->next->next->prior = p;
    // free(p);              //释放结点空间
    // return true;
}
//删除双链表
void DestoryList(DLinkList L)
{
    while (L->next != NULL)
    {
        DLinkLisDelete(L,1);
    }
}




int main()
{
    //[1]不带头结点的声明定义双链表
    DLinkList L = NULL;
    //[2]带头节点的声明定义双链表
    L = DLinkListInit();
    //[3]测试:插入结点
    DLinkListInsert(L,1,1);
    DLinkListInsert(L,1,2);
    DLinkListInsert(L,1,3);
    DLinkListInsert(L,1,4);
    DLinkListInsert(L,1,5);
    DLinkListInsert(L,1,6);
    DLinkListInsert(L,1,7);
    DLinkListInsert(L,1,8);
    DLinkListInsert(L,1,9);
    DLinkListInsert(L,1,10);
    DLinkListInsert(L,1,11);
    DLinkListInsert(L,1,12);
    PrintDLinkList(L);
    DLinkListInsert(L,4,888);
    DLinkListInsert(L,7,1022);
    DLinkListInsert(L,9,963);
    DLinkListInsert(L,11,8522);
    DLinkListInsert(L,100,150);
    DLinkListInsert(L,4,12000);
    DLinkListInsert(L,8,17869);
    PrintDLinkList(L);
    DLinkLisDelete(L,8);
    PrintDLinkList(L);
    DestoryList(L);
    free(L);
    L = NULL;
    PrintDLinkList(L);
    // DNode* node = LocateElem(L,150);
    // printf("Node.data = %d",node->data);
return 0;
}

运行效果图

在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-29 09:37:13  更:2021-08-29 09:39:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 8:28:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计