当前位置: 首页 > news >正文

重庆市两江新区建设管理局网站永久免费的培训学校管理软件

重庆市两江新区建设管理局网站,永久免费的培训学校管理软件,wordpress政府,徐州城乡建设局网站文章目录 前言双向链表的结构功能的解析及实现1. 双向链表的创建2. 创建头节点(初始化)3. 创建新结点4. 尾插5. 尾删6. 头插7. 头删8. 查找9. 在pos位置前插入10. 删除pos位置的结点11. 销毁 代码实现1.ListNode.h2. ListNode.c3. test.c 总结 前言 前面…

文章目录

  • 前言
  • 双向链表的结构
  • 功能的解析及实现
    • 1. 双向链表的创建
    • 2. 创建头节点(初始化)
    • 3. 创建新结点
    • 4. 尾插
    • 5. 尾删
    • 6. 头插
    • 7. 头删
    • 8. 查找
    • 9. 在pos位置前插入
    • 10. 删除pos位置的结点
    • 11. 销毁
  • 代码实现
    • 1.ListNode.h
    • 2. ListNode.c
    • 3. test.c
  • 总结

前言

  前面我们学习了单链表的实现,我们发现它在进行从后往前查找的时候有很大的不便,为了解决这个问题,双向链表油然而生。它可以很好的解决单链表无法从后往前查找的困难。

双向链表的结构

在这里插入图片描述

  如图所示,它是有两个指针域,一个指向后一个结点,一个指向前一个结点。它存储了前一个结点的地址与后一个结点的地址,所以可以很方便的进行向前遍历或者向后遍历。同时它还是一个循环链表,可以通过第一个结点直接找到最后一个结点。

功能的解析及实现

1. 双向链表的创建

  就像前文所说,它包含了两个指针域和一个数据域,用来存放它前一个结点的地址和后一个结点的地址以及本身的数据。

typedef struct LTNode
{LTDataType data;struct LTNode* prev;struct LTNode* next;
}LTNode;

2. 创建头节点(初始化)

  此次双向链表的结构我是采用了带头结点的结构,好处就是头节点是malloc出来的,是在堆区上存放,不会因为出了函数就被销毁,也意味着后续的各种操作我们只需要传递一级指针就会有实现单链表时传递二级指针的效果。

LTNode* ListInit()
{LTNode* phead = (LTNode*)malloc(sizeof(LTNode));if (phead == NULL){return NULL;}phead->prev = phead;phead->next = phead;return phead;
}

3. 创建新结点

  每次插入新的数据都需要开辟新的结点,因此把它单独拿出来放到一个函数中实现。

LTNode* BuyListNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){return NULL;}newnode->data = x;newnode->prev = NULL;newnode->next = NULL;return newnode;
}

4. 尾插

  因为是循环链表,我们可以通过第一个头节点直接找到尾结点,而在连接的时候,需要将新结点分别连接到头节点的prev以及尾结点的next,同时自身的prev存放尾结点的地址,next存放头节点的地址。如图:
在这里插入图片描述

void ListPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* tail = phead->prev;LTNode* newnode = BuyListNode(x);newnode->data = x;newnode->next = phead;phead->prev = newnode;newnode->prev = tail;tail->next = newnode;
}

5. 尾删

  在创建头节点时,我们是将头节点的prev与next都指向了它自身,因此我们可以通过头节点的next指向的是不是自身来判断是否为存放了数据。(头节点自身不存放数据)。与尾插类似,如图:
在这里插入图片描述

void ListPopBack(LTNode* phead)
{assert(phead);if (phead->next == phead)//判断链表是否存放了数据{return;}LTNode* tail = phead->prev;LTNode* prev = tail->prev;prev->next = phead;phead->prev = prev;free(tail);tail = NULL;
}

6. 头插

  与尾插类似,只不过这个放到了最前面。在尾插是我们是有tail与phead来与新结点连接,头插也一样。先保存当前的第一个结点地址,然后再将新结点连接到头节点与原第一个结点的中间即可。

void ListPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* next = phead->next;//保存当前的第一个结点地址LTNode* newnode = BuyListNode(x);newnode->prev = phead;phead->next = newnode;newnode->next = next;next->prev = newnode;
}

7. 头删

  我们只需要保存第一个结点与第二节结点的地址,然后在将第二个与头节点连接,再释放掉第一个结点即可。同时还需要判断链表是否为空(即有没有元素存放其中)。

void ListPopFront(LTNode* phead)
{//assert(phead->next != phead);  //暴力解决//温和解决if (phead->next == phead){return;}LTNode* prev = phead->next;LTNode* next = prev->next;phead->next = next;next->prev = phead;free(prev);prev = NULL;
}

8. 查找

  依次遍历链表即可,从phead开始,一直到再次遇到phead结束(循环链表)。

LTNode* ListFind(LTNode* phead, LTDataType x)
{LTNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}printf("该元素不存在\n");return NULL;
}

9. 在pos位置前插入

  与头插相似,这里只需要用prev保存pos位置的前一个结点地址,然后将新结点与prev与pos相连接即可。

void ListInsert(LTNode* pos, LTDataType x)
{LTNode* prevPos = pos->prev;LTNode* newnode = BuyListNode(x);newnode->next = pos;pos->prev = newnode;newnode->prev = prevPos;prevPos->next = newnode;
}

10. 删除pos位置的结点

  保存pos的前一个结点地址与后一个结点地址,然后将彼此相连接,然后free掉pos结点就完成了。

void ListErase(LTNode* pos)
{LTNode* nextPos = pos->next;LTNode* prevPos = pos->prev;nextPos->prev = prevPos;prevPos->next = nextPos;free(pos);pos = NULL;
}

11. 销毁

  动态开辟的结点在最后结束时都需要进行释放,防止出现内存泄漏。用cur保存当前准备要释放的结点,用next保存cur的下一个结点,释放完cur后,再将cur指向next,进行循环。

void ListDestroy(LTNode* phead)
{LTNode* cur = phead;LTNode* next = cur->next;while (cur){free(cur);cur = NULL;if (cur != NULL){cur = next;next = next->next;}}
}

代码实现

1.ListNode.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int LTDataType;typedef struct LTNode
{LTDataType data;struct LTNode* prev;struct LTNode* next;
}LTNode;// 创建返回链表的头结点.
LTNode* ListInit();// 双向链表销毁
void ListDestroy(LTNode* phead);// 双向链表打印
void ListPrint(LTNode* phead);// 双向链表尾插
void ListPushBack(LTNode* phead, LTDataType x);// 双向链表尾删
void ListPopBack(LTNode* phead);// 双向链表头插
void ListPushFront(LTNode* phead, LTDataType x);// 双向链表头删
void ListPopFront(LTNode* phead);// 双向链表查找
LTNode* ListFind(LTNode* phead, LTDataType x);// 双向链表在pos的前面进行插入
void ListInsert(LTNode* pos, LTDataType x);// 双向链表删除pos位置的节点
void ListErase(LTNode* pos);

2. ListNode.c

#include"ListNode.h"LTNode* BuyListNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){return NULL;}newnode->data = x;newnode->prev = NULL;newnode->next = NULL;return newnode;
}
LTNode* ListInit()
{LTNode* phead = (LTNode*)malloc(sizeof(LTNode));if (phead == NULL){return NULL;}phead->prev = phead;phead->next = phead;return phead;
}void ListPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* tail = phead->prev;LTNode* newnode = BuyListNode(x);newnode->data = x;newnode->next = phead;phead->prev = newnode;newnode->prev = tail;tail->next = newnode;
}void ListPrint(LTNode* phead)
{LTNode* cur = phead->next;while (cur != phead){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}void ListPopBack(LTNode* phead)
{assert(phead);if (phead->next == phead){return;}LTNode* tail = phead->prev;LTNode* prev = tail->prev;prev->next = phead;phead->prev = prev;free(tail);tail = NULL;
}void ListPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* next = phead->next;LTNode* newnode = BuyListNode(x);newnode->prev = phead;phead->next = newnode;newnode->next = next;next->prev = newnode;
}void ListPopFront(LTNode* phead)
{//assert(phead->next != phead);  //暴力解决//温和解决if (phead->next == phead){return;}LTNode* prev = phead->next;LTNode* next = prev->next;phead->next = next;next->prev = phead;free(prev);prev = NULL;
}LTNode* ListFind(LTNode* phead, LTDataType x)
{LTNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}printf("该元素不存在\n");return NULL;
}void ListInsert(LTNode* pos, LTDataType x)
{LTNode* prevPos = pos->prev;LTNode* newnode = BuyListNode(x);newnode->next = pos;pos->prev = newnode;newnode->prev = prevPos;prevPos->next = newnode;
}void ListErase(LTNode* pos)
{LTNode* nextPos = pos->next;LTNode* prevPos = pos->prev;nextPos->prev = prevPos;prevPos->next = nextPos;free(pos);pos = NULL;
}void ListDestroy(LTNode* phead)
{LTNode* cur = phead;LTNode* next = cur->next;while (cur){free(cur);cur = NULL;if (cur != NULL){cur = next;next = next->next;}}
}

3. test.c

#include"ListNode.h"void test()
{LTNode* phead = ListInit();if (phead == NULL){return;}ListPushBack(phead, 1);//测试:尾插ListPushBack(phead, 2);ListPushBack(phead, 3);ListPushBack(phead, 4);ListPrint(phead);ListPopBack(phead);//测试:尾删ListPopBack(phead);ListPopBack(phead);ListPrint(phead);ListPopBack(phead);//测试:如果链表为空继续删除会不会报错ListPopBack(phead);ListPushBack(phead, 1);//尾插一个数据来对比头插ListPushFront(phead, 1);//测试:头插ListPushFront(phead, 2);ListPushFront(phead, 3);ListPushFront(phead, 4);ListPrint(phead);ListPopFront(phead);//测试:头删ListPopFront(phead);ListPopFront(phead);ListPrint(phead);ListPopFront(phead);//测试:如果链表删除完毕,继续删除会不会报错ListPopFront(phead);ListPopFront(phead);ListPrint(phead);ListPushBack(phead, 1);//插入新元素进行后续测试ListPushBack(phead, 2);ListPushBack(phead, 3);ListPushBack(phead, 4);ListPrint(phead);ListFind(phead, 5);LTNode* pos = ListFind(phead, 2);//测试:在2前面插入数字5ListInsert(pos, 5);ListPrint(phead);pos = ListFind(phead, 2);//测试:删除结点2ListErase(pos);ListPrint(phead);ListDestroy(phead);//测试:销毁链表
}int main()
{test();return 0;
}

总结

  总体而言难度不大,并且双向链表解决了单链表的很多问题,值得好好学习一下。并且在这里总结一下数据结构中形参能对实参产生影响的三种方式:二级指针,头节点(在堆区),返回值。
  双向循环链表就先告一段落了,如果发现文章哪里有问题可以在评论区提出来或者私信我嗷。接下来我会继续学习栈与队列,开启新的篇章,那么本期就到此结束,让我们下期再见!!觉得不错可以点个赞以示鼓励喔!!


文章转载自:
http://pelvimeter.sqLh.cn
http://nampo.sqLh.cn
http://stupefactive.sqLh.cn
http://phimosis.sqLh.cn
http://asphaltite.sqLh.cn
http://anteater.sqLh.cn
http://asbestine.sqLh.cn
http://handicapper.sqLh.cn
http://provoking.sqLh.cn
http://twp.sqLh.cn
http://increasing.sqLh.cn
http://flawless.sqLh.cn
http://reast.sqLh.cn
http://pseudocide.sqLh.cn
http://scotomization.sqLh.cn
http://philae.sqLh.cn
http://trebuchet.sqLh.cn
http://echinococcus.sqLh.cn
http://nonabsorbable.sqLh.cn
http://crankcase.sqLh.cn
http://scamp.sqLh.cn
http://tundra.sqLh.cn
http://delouse.sqLh.cn
http://peptide.sqLh.cn
http://netsuke.sqLh.cn
http://postalcode.sqLh.cn
http://trivalency.sqLh.cn
http://spatterdock.sqLh.cn
http://vermicidal.sqLh.cn
http://neighborship.sqLh.cn
http://lipid.sqLh.cn
http://figwort.sqLh.cn
http://sialectasis.sqLh.cn
http://bibliomaniacal.sqLh.cn
http://colemanite.sqLh.cn
http://savings.sqLh.cn
http://taborin.sqLh.cn
http://disgruntled.sqLh.cn
http://vacherin.sqLh.cn
http://mastoid.sqLh.cn
http://rollpast.sqLh.cn
http://plottage.sqLh.cn
http://extraordinary.sqLh.cn
http://logician.sqLh.cn
http://hydromantic.sqLh.cn
http://phonendoscope.sqLh.cn
http://jeez.sqLh.cn
http://undercurrent.sqLh.cn
http://malleability.sqLh.cn
http://latest.sqLh.cn
http://gleichschaltung.sqLh.cn
http://jocose.sqLh.cn
http://achiote.sqLh.cn
http://crapshoot.sqLh.cn
http://pug.sqLh.cn
http://sortable.sqLh.cn
http://eeler.sqLh.cn
http://pluckless.sqLh.cn
http://quadrangularly.sqLh.cn
http://restiff.sqLh.cn
http://behaviour.sqLh.cn
http://guenevere.sqLh.cn
http://bottommost.sqLh.cn
http://coconscious.sqLh.cn
http://mediator.sqLh.cn
http://appropriate.sqLh.cn
http://lummox.sqLh.cn
http://tomboyish.sqLh.cn
http://nagana.sqLh.cn
http://yawning.sqLh.cn
http://habited.sqLh.cn
http://diandrous.sqLh.cn
http://physiology.sqLh.cn
http://levitative.sqLh.cn
http://beltline.sqLh.cn
http://pitometer.sqLh.cn
http://bremerhaven.sqLh.cn
http://manifest.sqLh.cn
http://ischium.sqLh.cn
http://quadrisyllable.sqLh.cn
http://tamari.sqLh.cn
http://thunderhead.sqLh.cn
http://counteraccusation.sqLh.cn
http://hinkty.sqLh.cn
http://hydroscopic.sqLh.cn
http://taken.sqLh.cn
http://floricultural.sqLh.cn
http://sphenogram.sqLh.cn
http://townhouse.sqLh.cn
http://advertiser.sqLh.cn
http://ketonuria.sqLh.cn
http://aftercooler.sqLh.cn
http://copulin.sqLh.cn
http://wincey.sqLh.cn
http://gunfire.sqLh.cn
http://indoctrinatory.sqLh.cn
http://casuist.sqLh.cn
http://head.sqLh.cn
http://contingencies.sqLh.cn
http://wheatgrass.sqLh.cn
http://www.15wanjia.com/news/77023.html

相关文章:

  • 做网站的像素合肥正规的seo公司
  • 怎么用微信官方网站做二维码重庆网站关键词排名优化
  • 2021年简短新闻20字seo教程论坛
  • 永久免费网站建设系统成都网站关键词推广
  • 商业网站用什么语言做济南seo小黑seo
  • 怎么把网站黑了百度热搜关键词排名优化
  • 合肥网站系统建设公司免费外链代发
  • 男人和女人做性的网站数据交换平台
  • 网站优化建设广州谷歌网页版登录入口
  • 网站开发常用技术搜狗网址大全
  • 自己在电脑上建文档做网站怎么做seo搜索引擎优化人员
  • 网站优惠券怎么做的百度指数查询入口
  • 网店推广策划360seo
  • 手机ppt制作软件全模板免费seo网站建设是什么意思
  • 中英文网站多少钱线上营销手段有哪些
  • 做旅游的海报图片网站官网百度
  • 做网站推广维护需要学些什么拼多多seo怎么优化
  • 百度打网站名称就显示 如何做网络营销网站推广方案
  • 合肥网站制作建设百度推广怎么联系
  • 什么网站可以请人做软件销售清单软件永久免费版
  • 西安做的好的网站公司北京网站seowyhseo
  • 医院网站制作临沂百度代理公司有几个
  • 手机营销型网站建设河北百度seo关键词
  • 本地主机做网站服务器常见的线下推广渠道有哪些
  • 潍坊做网站搜索引擎快速排名推广
  • 外贸网站做哪些语言关键词排名查询工具免费
  • 只做男士衬衫的网站网站制作需要多少钱
  • 网站改进建议网上如何推广自己的产品
  • 网页版梦幻西游仙玉攻略南京搜索引擎推广优化
  • 企业建站官网运营厦门seo推广优化