数据结构实验二之线性表(下)

实验题5:实现循环双链表的各种基本运算的算法

题目描述

编写一个程序cdlinklist.cpp,实现循环双链表的各种基本运算和整体建表算法

(假设循环双链表的元素类型ElemType为int),并在此基础上设计一个程序exp2-5.cpp

完成以下功能。

(1)初始化循环双链表h。

(2)依次采用尾插法插入元素a、b、c、d、e。

(3)输出循环双链表h。

(4)输出循环双链表h的长度。

(5)判断循环双链表h是否为空。

(6)输出循环双链表的第3个元素。

(7)输出元素a的位置。

(8)在第4个元素的位置上插入元素i

(9)输出循环双链表。

(10)副除循环双链表的第3个元素。

(11)输出循环双链表。

(12)释放循环双链表L。

算法:cdlinklist.cpp程序,其中包含如下函数。

· InitList(DLinkNode*&L),初始化循环双链表L。

· DestroyList(DLinkNode *I.):释放循环双链表L。

· ListEmpty(DLinkNode *L):判断循环双链表L是否为空表。

· ListLength(DLinkNode*L):返回循环双链表I中的元素个数。

· DispList(DLinkNode *L);输出循环双链表L。

• GetElem(DLinkNode*L.int i,ElemType &e);获取循环双链表L中的第i个元素。

· LocateElem(DLinkNode*L,ElemType e);在循环双链表L中查找元素e。

· ListInsert(DLinkNode&L,int i,ElemType e),在循环双链表L中的第i个位置上插入元素e。

· ListDelete(DLinkNode * &L,int i,ElemType &e):从循环双链表L中删除第i个元素。

运行代码

cdlinklist.cpp
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>typedef int ElemType;
typedef struct DNode
{ElemType data;struct DNode* prior;struct DNode* next;
} DLinkNode;// 头插法创建循环双链表
void CreateListF(DLinkNode*& L, ElemType a[], int n)
{DLinkNode* s;// 分配头结点空间L = (DLinkNode*)malloc(sizeof(DLinkNode));L->next = NULL;// 遍历数组,用头插法插入节点for (int i = 0; i < n; i++){s = (DLinkNode*)malloc(sizeof(DLinkNode));s->data = a[i];// 将新节点插入头结点之后s->next = L->next;if (L->next != NULL) L->next->prior = s;L->next = s;s->prior = L;}// 找到尾结点s = L->next;while (s->next != NULL){s = s->next;}// 尾结点的 next 指向头结点s->next = L;// 头结点的 prior 指向尾结点L->prior = s;
}// 尾插法创建循环双链表
void CreateListR(DLinkNode*& L, ElemType a[], int n)
{DLinkNode* s, * r;// 分配头结点空间,初始化头结点的 next 和 prior 指向自身L = (DLinkNode*)malloc(sizeof(DLinkNode));L->next = L;L->prior = L;r = L;// 遍历数组,用尾插法插入节点for (int i = 0; i < n; i++){s = (DLinkNode*)malloc(sizeof(DLinkNode));s->data = a[i];// 将新节点插入尾结点之后r->next = s;s->prior = r;r = s;}// 尾结点的 next 指向头结点r->next = L;// 头结点的 prior 指向尾结点L->prior = r;
}// 初始化循环双链表
void InitList(DLinkNode*& L)
{// 分配头结点空间,初始化头结点的 next 和 prior 指向自身L = (DLinkNode*)malloc(sizeof(DLinkNode));L->prior = L;L->next = L;
}// 销毁循环双链表
void DestroyList(DLinkNode*& L)
{DLinkNode* pre = L, * p = pre->next;// 遍历链表释放节点内存while (p != L){free(pre);pre = p;p = p->next;}// 释放最后一个节点(此时 pre 指向最后一个节点)free(pre);
}// 判断循环双链表是否为空
bool ListEmpty(DLinkNode* L)
{return L->next == L;
}// 求循环双链表的长度
int ListLength(DLinkNode* L)
{DLinkNode* p = L;int i = 0;// 遍历链表计算长度while (p->next != L){p = p->next;i++;}return i;
}// 输出循环双链表
void DispList(DLinkNode* L)
{DLinkNode* p = L->next;// 遍历链表输出节点数据while (p != L){printf("%c ", p->data);p = p->next;}printf("\n");
}// 求循环双链表中第 i 个元素的值
bool GetElem(DLinkNode* L, int i, ElemType& e)
{int j = 1;DLinkNode* p = L;if (i <= 0) return false;if (i == 1){// 提取第一个节点的值e = L->next->data;return true;}p = L->next;while (j < i && p != L){j++;p = p->next;}if (p == L)return false;else{// 提取第 i 个节点的值e = p->data;return true;}
}// 查找第一个值域为 e 的元素的序号
int LocateElem(DLinkNode* L, ElemType e)
{int i = 1;DLinkNode* p = L->next;// 遍历链表查找特定值的节点while (p != L && p->data != e){p = p->next;i++;}if (p == L)return 0;elsereturn i;
}// 在循环双链表中插入第 i 个元素
bool ListInsert(DLinkNode*& L, int i, ElemType e)
{int j = 1;DLinkNode* p = L, * s;if (i <= 0) return false;if (L->next == L){// 链表为空时插入节点s = (DLinkNode*)malloc(sizeof(DLinkNode));s->data = e;s->next = L;s->prior = L;L->next = s;L->prior = s;return true;}if (i == 1){// 在第一个位置插入节点s = (DLinkNode*)malloc(sizeof(DLinkNode));s->data = e;s->next = L->next;L->next->prior = s;s->prior = L;L->next = s;return true;}p = L->next;while (j < i - 1 && p != L){j++;p = p->next;}if (p == L)return false;else{s = (DLinkNode*)malloc(sizeof(DLinkNode));s->data = e;s->next = p->next;if (p->next != L) p->next->prior = s;s->prior = p;p->next = s;return true;}
}// 删除循环双链表中第 i 个元素
bool ListDelete(DLinkNode*& L, int i, ElemType& e)
{int j = 1;DLinkNode* p = L, * q;if (i <= 0 || L->next == L)return false;if (i == 1){// 删除第一个元素q = L->next;e = q->data;L->next = q->next;if (q->next != L) q->next->prior = L;free(q);return true;}p = L->next;while (j < i - 1 && p != L){j++;p = p->next;}if (p == L)return false;else{q = p->next;if (q == L) return false;e = q->data;p->next = q->next;if (q->next != L) q->next->prior = p;free(q);return true;}
}
excp2-5.cpp
#include <stdio.h>
#include <stdlib.h>
#include "cdlinklist.cpp"int main() {DLinkNode* h;ElemType e;printf("循环双链表的基本运算如下:\n");printf("(1)初始化循环双链表 h\n");InitList(h);printf("(2)依次采用尾插法插入元素 a,b,c,d,e\n");ListInsert(h, 1, 'a');ListInsert(h, 2, 'b');ListInsert(h, 3, 'c');ListInsert(h, 4, 'd');ListInsert(h, 5, 'e');printf("(3)输出循环双链表 h:");DispList(h);printf("(4)循环双链表 h 长度:%d\n", ListLength(h));printf("(5)循环双链表 h 为%s\n", (ListEmpty(h) ? "空" : "非空"));GetElem(h, 3, e);printf("(6)循环双链表 h 的第 3 个元素:%c\n", e);printf("(7)元素 a 的位置:%d\n", LocateElem(h, 'a'));printf("(8)在第 4 个元素位置上插入元素 f\n");ListInsert(h, 4, 'f');printf("(9)输出循环双链表 h:");DispList(h);printf("(10)删除 h 的第 3 个元素\n");ListDelete(h, 3, e);printf("(11)输出循环双链表 h:");DispList(h);printf("(12)释放循环双链表 h\n");DestroyList(h);return 1;
}

代码结果与思路

定义了一个循环双链表的节点结构体DNode(重命名为DLinkNode),包含以下成员:

  • data:存储节点的数据,这里数据类型为ElemType,实际上是int类型。
  • prior:指向前驱节点的指针。
  • next:指向后继节点的指针。
  1. 创建链表函数

    • 头插法创建循环双链表(CreateListF
      • 首先为头结点分配内存空间,并将头结点的next指针置为NULL
      • 然后遍历输入的数组,对于数组中的每个元素:分配新节点s的内存空间。将新节点s的数据域设置为当前数组元素的值。将新节点s插入到头结点之后,具体操作是让新节点的next指针指向原来头结点的下一个节点,如果原来头结点有下一个节点,则让原来头结点的下一个节点的前驱指针指向新节点;再让头结点的next指针指向新节点,新节点的前驱指针指向头结点。
      • 接着找到尾结点,即从新的头结点开始遍历,直到找到next指针为NULL的节点。
      • 让尾结点的next指针指向头结点,同时让头结点的prior指针指向尾结点,形成循环双链表。
    • 尾插法创建循环双链表(CreateListR
      • 同样先为头结点分配内存空间,并将头结点的nextprior指针都指向自身,形成只有一个头结点的循环双链表。
      • 设置一个指针r指向头结点,作为尾指针。
      • 遍历输入数组,对于每个元素:分配新节点s的内存空间。将新节点s的数据域设置为当前数组元素的值。将新节点s插入到尾指针r之后,具体操作是让尾指针rnext指针指向新节点,新节点的前驱指针指向尾指针r;然后更新尾指针r为新节点。
      • 最后让尾指针的next指针指向头结点,同时让头结点的prior指针指向尾指针,形成循环双链表。
  2. 初始化链表函数(InitList:为循环双链表分配头结点空间,并将头结点的nextprior指针都指向自身,形成只有一个头结点的循环双链表。

  3. 销毁链表函数(DestroyList

    • 从链表的第一个有效节点开始,依次释放每个节点的内存空间。设置两个指针preppre初始指向头结点,p初始指向头结点的下一个节点。
    • p不等于头结点时,释放pre所指节点的内存空间,然后将pre指向pp指向p的下一个节点。
    • p等于头结点时,说明链表中的所有节点都已释放,再释放pre所指的头结点的内存空间。
  4. 判断链表是否为空函数(ListEmpty:只需要检查头结点的next指针是否指向自身,如果是,则链表为空,返回true;否则返回false

  5. 求链表长度函数(ListLength

    • 从链表的第一个有效节点开始遍历,设置一个指针p指向头结点的下一个节点,设置一个计数器i初始值为 0。
    • pnext指针不等于头结点时,说明还有节点未遍历,计数器i加一,移动指针p指向下一个节点。
    • 遍历结束后,返回计数器i的值,即为链表的长度。
  6. 输出链表函数(DispList

    • 从链表的第一个有效节点开始输出,设置一个指针p指向头结点的下一个节点。
    • p不等于头结点时,输出p所指节点的数据域,然后移动指针p指向下一个节点,继续输出直到回到头结点。
  7. 求链表中第 i 个元素的值函数(GetElem

    • 首先检查输入的序号i是否合法(大于 0),如果不合法则返回false
    • 如果i等于 1,直接提取头结点的下一个节点的值并返回true
    • 如果i大于 1,设置一个指针p指向头结点的下一个节点,一个计数器j初始值为 1。
    • j小于ip不等于头结点时,计数器j加一,移动指针p指向下一个节点,目的是找到第i个节点。
    • 如果遍历结束后p等于头结点,说明没有找到第i个节点,返回false;否则将p所指节点的数据域赋值给参数e,并返回true
  8. 查找第一个值域为 e 的元素的序号函数(LocateElem

    • 从链表的第一个有效节点开始查找,设置一个计数器i初始值为 1,设置一个指针p指向头结点的下一个节点。
    • p不等于头结点且p所指节点的数据域不等于要查找的值e时,计数器i加一,移动指针p指向下一个节点。
    • 如果遍历结束后p等于头结点,说明没有找到值为e的节点,返回 0;否则返回计数器i的值,即找到的节点的序号。
  9. 在链表中插入第 i 个元素函数(ListInsert

    • 首先检查输入的序号i是否合法(大于 0),如果不合法则返回false
    • 如果链表为空,即头结点的next指针指向自身,直接在头结点之后插入新节点,具体操作是分配新节点s的内存空间,设置新节点的数据域为要插入的值e,让新节点的nextprior指针分别指向头结点和头结点的前驱指针,再让头结点的next和前驱指针分别指向新节点。
    • 如果i等于 1,直接在头结点之后插入新节点,具体操作是分配新节点s的内存空间,设置新节点的数据域为要插入的值e,让新节点的next指针指向头结点的下一个节点,新节点的前驱指针指向头结点,然后让头结点的下一个节点的前驱指针指向新节点,头结点的next指针指向新节点。
    • 如果i大于 1,设置一个指针p指向头结点的下一个节点,一个计数器j初始值为 1。
    • j小于i - 1p不等于头结点时,计数器j加一,移动指针p指向下一个节点,目的是找到要插入位置的前一个节点。
    • 如果遍历结束后p等于头结点,说明没有找到要插入位置的前一个节点,返回false
    • 分配新节点s的内存空间,设置新节点的数据域为要插入的值e
    • 将新节点s插入到节点p之后,具体操作是让新节点的next指针指向p的下一个节点,如果p有下一个节点,则让p的下一个节点的前驱指针指向新节点;再让新节点的前驱指针指向ppnext指针指向新节点。
  10. 删除链表中第 i 个元素函数(ListDelete

  • 首先检查输入的序号i是否合法(大于 0)以及链表是否为空,如果不合法或链表为空则返回false
  • 如果i等于 1,直接删除头结点的下一个节点,具体操作是设置一个指针q指向头结点的下一个节点,将q所指节点的数据域赋值给参数e,让头结点的next指针指向q的下一个节点,如果q的下一个节点存在,则让q的下一个节点的前驱指针指向头结点,最后释放q所指节点的内存空间,并返回true
  • 如果i大于 1,设置一个指针p指向头结点的下一个节点,一个计数器j初始值为 1。
  • j小于i - 1p不等于头结点时,计数器j加一,移动指针p指向下一个节点,目的是找到要删除节点的前一个节点。
  • 如果遍历结束后p等于头结点,说明没有找到要删除节点的前一个节点,返回false
  • 设置一个指针q指向p的下一个节点,如果q等于头结点,说明不存在第i个节点,返回false
  • q所指节点的数据域赋值给参数e,然后将节点q从链表中删除,具体操作是让pnext指针指向q的下一个节点,如果q的下一个节点存在,则让q的下一个节点的前驱指针指向p,最后释放q所指节点的内存空间,并返回true

这段代码实现了循环双链表的一系列基本操作,包括创建链表(头插法和尾插法)、初始化链表、判断链表是否为空、求链表长度、输出链表、查找链表中特定位置的元素、查找特定值在链表中的位置、在链表中插入元素和从链表中删除元素以及销毁链表等功能。通过这些函数的组合使用,可以方便地对循环双链表进行各种操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/148779.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

免费的 H5/PC 地图打卡 —— 功能代码及实现指南/功能代码已上传

在本文中&#xff0c;我们将通过天地图&#xff08;Tianditu&#xff09;实现一个简单的 H5/PC 版地图打卡功能。通过实时获取用户的位置&#xff0c;检测其与打卡点的距离&#xff0c;来决定是否可以完成打卡。代码已上传&#xff0c;本文将逐步介绍如何实现这一功能。 效果图…

EDI简化,两剂初免效果好

EDI简化&#xff0c;两剂初免效果好 大家好&#xff0c;疫苗是防控传染病的重要工具。但对于一些如HIV等病原体&#xff0c;有效疫苗的研发仍面临诸多挑战。在疫苗接种中&#xff0c;生发中心起着关键作用。近期研究表明——《Two-dose priming immunization amplifies humoral…

[数据集][目标检测]基于yolov5增强数据集算法mosaic来扩充自己的数据集自动生成增强图片和对应标注无需重新标注

【算法介绍】 YOLOv5最引人注目的增强技术之一是马赛克增强&#xff0c;它将四张不同的图像拼接成一张图像。 思路&#xff1a;首先&#xff0c;从数据集中随机选择四张图像&#xff0c;然后将它们缩放、随机裁剪&#xff0c;并按马赛克模式拼接在一起。这种方式允许模型看到…

为什么AI不会夺去软件工程师的工作?

▼ 自从AI大模型爆火以来&#xff0c;我每天的工作中&#xff0c;已经有大量的真实代码是通过AI完成的。人工智能辅助下的编程&#xff0c;确实大幅减轻了我的工作负担&#xff0c;大大提高了生产力。 大语言模型是如此成功&#xff0c;以至于无可避免地在开发者社区中引起了…

DesignMode__unity__抽象工厂模式在unity中的应用、用单例模式进行资源加载

目录 抽象工厂模式 思维导图 接口&#xff08;抽象类&#xff09; 工厂接口 抽象产品类 抽象武器接口 抽象人物接口 具体工厂和具体产品 具体工厂 &#xff08;1&#xff09;产品接口&#xff0c;生成具体人物 &#xff08;2&#xff09;武器接口&#xff0c;生成具体…

mapboxGL 离线部署或者说去除token最简单得方法

找到本项目中得node_modules包管理器中得mapbox-gl包 找打dist文件夹下得mapbox-gl-dev.js 相比于mapbox-gl.js得压缩文件 mapbox-gl-dev.js没有压缩&#xff0c;好修改&#xff0c;也无需要编译 在mapbox-gl-dev.js找到 this._authenticate()&#xff0c;注释或者去除即可 最…

【Proteus仿真】基于51单片机的简易电压表制作(可串口远程调控)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;设计一个简易电压表&#xff1a; 采用3位LED数码管显示被测电压值&#xff1a;基本测量范围是 0-5V&#xff1b;测量误差为士0.02V。开机或复位后&#xff0c;在 LED 最…

三角型电动采光排烟天窗的高效排烟设计优势

三角型电动采光排烟天窗的排烟效果在多个方面均展现出了显著的优势&#xff0c;主要体现在以下几个方面。一、设计原理与结构特性 三角型电动采光排烟天窗采用三角形构造&#xff0c;这种设计在结构上具有显著的稳定性&#xff0c;能够抵御不同气候条件及风压的影响。同时减少了…

网站建设合同怎么写

网站建设合同成为企业与网站开发服务提供商之间不可或缺的法律文书。一份明晰而全面的网站建设合同不仅有助于规范双方权责&#xff0c;还能有效防范潜在的合同纠纷。以下是一份网站建设合同的范本&#xff0c;旨在提供参考。 一、合同双方信息 甲方&#xff08;委托方&#x…

QT| “无法粘贴窗口部件”错误以及customplot安装使用

“无法粘贴窗口部件”错误以及customplot “无法粘贴窗口部件”错误customplot下载添加到项目中使用QCustomPlot常用的代码 “无法粘贴窗口部件”错误 情景&#xff1a;使用QT设计界面&#xff0c;很多部分比较类似&#xff0c;可以复制另一个界面的ui&#xff0c;但是粘粘的时…

TS-AI:一种用于多模态个体化脑区划分的深度学习管道,并结合任务对比合成|文献速递-Transformer架构在医学影像分析中的应用

Title 题目 TS-AI: A deep learning pipeline for multimodal subject-specific parcellation with task contrasts synthesis TS-AI&#xff1a;一种用于多模态个体化脑区划分的深度学习管道&#xff0c;并结合任务对比合成 01 文献速递介绍 人类大脑在结构和功能组织上表…

武汉正向科技 格雷母线检测方式 :车检,地检

正向科技|格雷母线原理运用-车检&#xff0c;地检 地上检测方式 地址编码器和天线箱安装在移动站上&#xff0c;通过天线箱发射地址信号&#xff0c;地址解码器安装在固定站&#xff08;地面&#xff09;上&#xff0c;在固定站完成地址检测。 车上检测方式 地址编码器安装在…

单域名、多域名、通配符SSL证书,该如何选择?

随着《网络安全法》《数据安全法》相关法律法规的发布&#xff0c;履行数据保护义务&#xff0c;做好数据安全保护是每个企业的重要工作。其中&#xff0c;SSL证书作为企业网站实现HTTPS加密保护数据传输安全的必备措施&#xff0c;根据域名保护数量&#xff0c;可以分为单域名…

拼团活动开发秘籍:PHP+Redis实现暂存成团信息,提升效率!

在用户发起成团&#xff0c;与用户入团时需要保存其成团信息&#xff08;主要是活动id与团长、团员openid&#xff09;&#xff0c;暂存在redis中&#xff0c;后期需要保存到sql中&#xff0c;以便查询。 tuan_redis.php<?php include_once(/opt/*****ub/redis.php);//red…

Java语言程序设计基础篇_编程练习题**18.35(H 树分形)

目录 题目&#xff1a;**18.35(H 树分形) 代码示例 代码解释 输出结果 题目&#xff1a;**18.35(H 树分形) 一个H 树分形(本章开始部分介绍过&#xff0c;如图18-1)如下定义: 1)从字母H开始。H的三条线长度一样&#xff0c;如图 18-1a 所示。 2)字母H(以它的 sans-serif …

若依vue3.0表格的增删改查文件封装

一、因若依生成的文件没进行封装&#xff0c;维护起来比较麻烦。所以自己简单的进行封装了一下 gitee代码&#xff08;文件&#xff09;地址&#xff1a;https://gitee.com/liu_yu_ting09/ruo_yi.git 二、封装的方法&#xff08;下面绿色按钮进行全局封装一个JeecgListMixin.js…

如何在局域网下测试vue项目

同一局域网下&#xff0c;通俗讲&#xff0c;就是电脑和手机等其他设备连接的是同一个 wifi 1 修改 vue 项目的 host 地址 vue项目一般使用 npm run dev 或者 npm run server 来运行如果是 webpack 构建的项目&#xff0c;在config文件夹下有一个index.js文件&#xff0c;找到…

汽车HMI:UI设计进入了3D时代,设计师准备好了吗?

汽车HMI中的低模是通过使用简化的图形和界面元素来实现的。这些低模通常是通过减少细节和精细度来实现的&#xff0c;以便在有限的处理能力和内存资源下实现更流畅的用户体验。 对UI设计师来说&#xff0c;低模的实现可能会带来一些挑战。 首先&#xff0c;他们需要考虑如何在…

基于51单片机的模拟8层电梯运行proteus仿真

地址&#xff1a; https://pan.baidu.com/s/1i_h6TnziwnPKKo37zlwWAg 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectro…

建立分支提交代码

git分支 git branch 产看当前分支 git branch -a 查看所有分支 git checkout 分支名 切换分支 git checkout -b 分支名 建立分支&#xff08;仅仅是在本地建立了&#xff0c;并没有关联线上&#xff09; git push --set-upstream origin 分支名 把本地分支推到先线上 建立分支…