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

免费咨询做网站公司做网站的 oa办公系统

免费咨询做网站,公司做网站的 oa办公系统,晋江免费网站建设,消防公司宣传册设计样本一、双向链表介绍 二、实现双向链表 1.定义双向链表的结构 2.双向链表的初始化 3.双向链表的尾插 4.双向链表的头插 5.双向链表的打印 6.双向链表的尾删 7.双向链表的头删 8.查找指定位置的数据 9.在指定位置之后插入数据 10.删除指定位置的数据 11.链表的销毁 三、…

一、双向链表介绍

二、实现双向链表

1.定义双向链表的结构

2.双向链表的初始化

3.双向链表的尾插

4.双向链表的头插

5.双向链表的打印

6.双向链表的尾删

7.双向链表的头删

8.查找指定位置的数据

9.在指定位置之后插入数据

10.删除指定位置的数据

11.链表的销毁

三、代码展示

一、双向链表介绍

双向链表就是带头双向循环链表,带头链表里的头结点,实际为"哨兵位",哨兵位节点不存储任何有效元素,它存在的意义是遍历循环链表避免死循环。哨兵位节点不能被删除,节点的地址也不能发生改变。

二、实现双向链表

1.定义双向链表的结构

我们看一张图,会发现,每个节点由三个部分组成:1.节点的数据 2.节点存放着指向下一个节点的指针next  3.节点存放着指向上一个节点的指针prev,所以我们定义如下:

typedef int LTData;//便于应用各种数据
typedef struct ListNode
{LTData data;//数据struct ListNode* next;//指向下一个节点的指针struct ListNode* prev;//指向上一个节点的指针
}LTNode;//重命名为LTNode方便表达

这个放在list.h里面,我们一共有三个文件,list.h list.c和test.c

2.双向链表的初始化

双向链表初始化,我们要初始化哨兵位,哨兵位没有值,所以节点里面没有有效的数据,那我们先完成一个前置函数LTBuyNode,用它来创建节点,步骤很简单:malloc开辟,然后检查是否开辟成功,成功就传数据。

注意:链表循环的条件是尾结点的next指针不为空,所以这里初始化的prev和next都指向节点本身,代码如下:

接着调用一下这个前置函数就可以了:

LTNode* LTBuyNode(LTData x)//创建节点
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));//malloc开辟一块空间if (node == NULL)//判断空间是否为空{perror("malloc fail!");exit(1);}node->data = x;//将数据给data//这里prev和next不能指向NULL,不然就是不循环了,所以让他们指向本身node->next = node->prev = node;return node;//返回节点
}
void LTInit(LTNode** pphead)
{*pphead = LTBuyNode(-1);//给双向链表创建一个哨兵位//哨兵位没有值,所以传一个-1
}

3.双向链表的尾插

双向链表的尾插有些复杂

1.双向链表是带环链表,所以是头尾相连的,如果设指向头结点的指针是phead,那么phead的prev指针指向的也就是尾结点。

2.尾插一个新节点,叫做newnode,那需要建立一个新节点,调用函数LTBuyNode();

3.现在有三个节点,分别是phead指向的头结点,phead->prev指向的尾结点以及要插入的节点newnode

4.newnode有两个指针,它现在是新的尾结点,所以她的next指针指向头结点phead,它的prev指针指向前一个节点也是就phead->prev指向的节点,那原来的尾结点的next指针也要改变,改完指向下一个节点也就是newnode,头结点的prev指针也要改变,现在它指向新的尾结点也就是newnode。

代码如下:     

void LTPushBack(LTNode* phead, LTData x)//传一级就够了,因为不用改变哨兵位的地址
{assert(phead);//断言确定不为空LTNode* newnode = LTBuyNode(x);//创建新节点//phead phead->prev newnodenewnode->prev = phead->prev;newnode->next = phead;phead->prev->next = newnode;phead->prev = newnode;
}

4.双向链表的头插

头插基本思路和尾插一样,需要注意的是头插是插在第一个有效节点之前,也就是哨兵位之后

1.先调用LTBuyNode()函数创建一个新节点newnode

2.要将newnode插在phead和phead->next之间

3.newnode的next指针指向phead->next;newnode的prev指针指向phead

4.phead->next指针指向的节点的prev指针改变指向,现在指向newnode,phead指向节点的next指针改变指向,现在指向newnode。

代码如下:

void LTPushFront(LTNode* phead, LTData x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//创建新节点//phead newnode phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}

5.双向链表的打印

双向链表的打印很简单,只需要遍历链表就可以,因为双向链表的第一个节点是哨兵位,不存储数据,所以我们只需要定义一个指针pcur指向头结点的下一个节点,然后循环就可以了,但是我们要知道循环的条件是什么,由于双向链表是带环链表,所以只需要让pcur不重新指回头结点即可。

代码如下:

        

void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;//第一个节点是哨兵位,不需要打印while (pcur != phead)//如果没有遍历回头结点,就不用停{printf("%d->", pcur->data);//打印每个节点的数据pcur = pcur->next;//节点往后遍历}printf("\n");
}

6.双向链表的尾删

1.明确要删的节点,头结点是phead,那phead->prev就是尾结点,也就是要删除的节点

2.定义一个新的指针del来接受phead->prev,那删除后,del->prev就是新节点

3.现在尾结点是del->prev,那它的next指针就是头结点,那头结点的prev指针也就是新的尾结点

4.记得释放掉del,并且将他置为空

代码如下:

void LTPopBack(LTNode* phead)
{//链表必须有效且链表不能为空assert(phead && phead->next != phead);LTNode* del = phead->prev;//phead del->prev deldel->prev->next = phead;phead->prev = del->prev;free(del);del = NULL;
}

7.双向链表的头删

头删思路和尾删差不多

1.定义一个新指针del是phead->next,也就是del要被删除

2.现在处理三个节点,分别是phead,del,del->next;

3.phead的next指针指向改变,改为指向del->next

4.del->next的prev指针指向改变,改为指向phead

5.最后记得free掉del,并将他置为NULL

代码如下:

void LTPopFront(LTNode* phead)
{//链表必须有效且链表不能为空assert(phead && phead->next != phead);LTNode* del = phead->next;phead->next = del->next;del->next->prev = phead;//删除del节点free(del);del = NULL;
}

8.查找指定位置的数据

查找就是遍历链表,定义一个指针pcur,当他没有循环一圈等于头结点phead的时候,就一直遍历;如果pcur指向的节点的data是要查找的数据,就返回,如果遍历完还是找不到,就返回NULL。

代码如下:

LTNode* LTFind(LTNode* phead, LTData x)
{LTNode* pcur = phead->next;//定义一个新指针,指向第一个有效的节点while (pcur != phead)//遍历双向链表{if (pcur->data == x)//如果找到了就返回pcur{return pcur;}pcur = pcur->next;//pcur每次向后移动一格}//没有找到return NULL;
}

在test.c里面测试一下:

9.在指定位置之后插入数据

这里就是三个节点:pos newnode pos->next

1.先用LTBuyNode()函数创立一个新节点newnode;

2.newnode的next指针指向pos->next

3.newnode的prev指针指向pos

4.pos->next指针指向的节点的prev改为指向newnode

5.pos指针指向的节点的next改为指向newnode

代码如下:

void LTInsert(LTNode* pos, LTData x)
{assert(pos);//断言防止为空LTNode* newnode = LTBuyNode(x);//pos newnode pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}

10.删除指定位置的数据

删除pos,就要关注三个节点,pos->prev、pos、pos->next

1.首先pos->next的这个节点的prev指向改变,改为指向pos->prev

2.pos->prev指向的节点的next改变,改为指向pos->next

3.记得销毁pos

代码如下:

void LTErase(LTNode* pos)
{assert(pos);//断言防止为空//pos->prev pos pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;//销毁posfree(pos);pos = NULL;
}

11.链表的销毁

最后一步是链表销毁,那只需要遍历双向链表,然后一个一个free就可以了,注意哨兵位也是初始化时候创建的,也要销毁。

代码如下:

void LTDestroy(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = pcur->next;}free(phead);phead = NULL;
}

三、代码展示

list.h:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int LTData;//便于应用各种数据
typedef struct ListNode
{LTData data;//数据struct ListNode* next;//指向下一个节点的指针struct ListNode* prev;//指向上一个节点的指针
}LTNode;//重命名为LTNode方便表达void LTInit(LTNode** pphead);
void LTPrint(LTNode* phead);
void LTPushBack(LTNode* phead, LTData x);//传一级就够了
void LTPushFront(LTNode* phead, LTData x);
void LTPopBack(LTNode* phead);
void LTPopFront(LTNode* phead);void LTInsert(LTNode* pos, LTData x);
void LTErase(LTNode* pos);
LTNode* LTFind(LTNode* phead, LTData x);
void LTDestroy(LTNode* phead);	 

list.c:

#include "list.h"void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;//第一个节点是哨兵位,不需要打印while (pcur != phead)//如果没有遍历回头结点,就不用停{printf("%d->", pcur->data);//打印每个节点的数据pcur = pcur->next;//节点往后遍历}printf("\n");
}LTNode* LTBuyNode(LTData x)//创建节点
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));//malloc开辟一块空间if (node == NULL)//判断空间是否为空{perror("malloc fail!");exit(1);}node->data = x;//将数据给data//这里prev和next不能指向NULL,不然就是不循环了,所以让他们指向本身node->next = node->prev = node;return node;//返回节点
}
void LTInit(LTNode** pphead)
{*pphead = LTBuyNode(-1);//给双向链表创建一个哨兵位//哨兵位没有值,所以传一个-1
}void LTPushBack(LTNode* phead, LTData x)//传一级就够了,因为不用改变哨兵位的地址
{assert(phead);//断言确定不为空LTNode* newnode = LTBuyNode(x);//创建新节点//phead phead->prev newnodenewnode->prev = phead->prev;newnode->next = phead;phead->prev->next = newnode;phead->prev = newnode;
}
void LTPushFront(LTNode* phead, LTData x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//创建新节点//phead newnode phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}void LTPopBack(LTNode* phead)
{//链表必须有效且链表不能为空assert(phead && phead->next != phead);LTNode* del = phead->prev;//phead del->prev deldel->prev->next = phead;phead->prev = del->prev;free(del);del = NULL;
}void LTPopFront(LTNode* phead)
{//链表必须有效且链表不能为空assert(phead && phead->next != phead);LTNode* del = phead->next;phead->next = del->next;del->next->prev = phead;//删除del节点free(del);del = NULL;
}LTNode* LTFind(LTNode* phead, LTData x)
{LTNode* pcur = phead->next;//定义一个新指针,指向第一个有效的节点while (pcur != phead)//遍历双向链表{if (pcur->data == x)//如果找到了就返回pcur{return pcur;}pcur = pcur->next;//pcur每次向后移动一格}//没有找到return NULL;
}void LTInsert(LTNode* pos, LTData x)
{assert(pos);//断言防止为空LTNode* newnode = LTBuyNode(x);//pos newnode pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}void LTErase(LTNode* pos)
{assert(pos);//断言防止为空//pos->prev pos pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;//销毁posfree(pos);pos = NULL;
}void LTDestroy(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = pcur->next;}free(phead);phead = NULL;
}

test.c:

#include "list.h"void test01()
{LTNode* plist = NULL;LTInit(&plist);LTPushBack(plist, 1);LTPushBack(plist, 1);LTPushBack(plist, 1);LTPushFront(plist, 3);LTPrint(plist);LTPopFront(plist);LTPrint(plist);
}void test02()
{LTNode* plist = NULL;LTInit(&plist);LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPrint(plist);LTNode* find = LTFind(plist, 1);if (find == NULL){printf("找不到!\n");}else{printf("找到了!\n");}}
int main()
{//test01();test02();return 0;
}


文章转载自:

http://6dcW2QIY.pdghL.cn
http://lNNNz9Tl.pdghL.cn
http://jBW4ihgz.pdghL.cn
http://M8u33Qn6.pdghL.cn
http://aVu6LKtD.pdghL.cn
http://kp1oXDSS.pdghL.cn
http://qjBLONUC.pdghL.cn
http://xRgYMGHX.pdghL.cn
http://nUpW02TW.pdghL.cn
http://Ya3a3VNj.pdghL.cn
http://V31Lkoc4.pdghL.cn
http://rbWAJ5ZR.pdghL.cn
http://NOU85jgt.pdghL.cn
http://I2ENNlCa.pdghL.cn
http://bRIcGhUH.pdghL.cn
http://M3E2ceim.pdghL.cn
http://yARAra4k.pdghL.cn
http://jwS1KR87.pdghL.cn
http://nRWcX9kw.pdghL.cn
http://8pvttHjg.pdghL.cn
http://VZ7Redbk.pdghL.cn
http://c5NXM2Jg.pdghL.cn
http://6uJvAvze.pdghL.cn
http://hfsOgJXd.pdghL.cn
http://4ptNTBur.pdghL.cn
http://S0gNqXsx.pdghL.cn
http://UtTiKUPg.pdghL.cn
http://IuWM1nHg.pdghL.cn
http://STpmluo7.pdghL.cn
http://iJabzO9q.pdghL.cn
http://www.dtcms.com/wzjs/734245.html

相关文章:

  • 重生做门户网站的小说支持ipv6网站开发
  • 自适应网站案例dz系统怎么做地方网站
  • html做的网站怎么发布共振设计公司官网
  • wordpress搭建子网站iis能搭WordPress
  • 外贸网站建设推广优化网站建设合同模式
  • 建安证查询网站如何制作网站二维码
  • 建设旅游网站数据库设计网站死链检测工具
  • 建导航网站园区做网站的好处
  • 吉林省网站制作公司有哪些网页游戏排行榜前十名3d
  • 深圳网站建设 东莞网站建设国外做外汇网站交流
  • 如何微信做演讲视频网站怎么推广微信小程序
  • 荆州网站建设 众火网wordpress写的网站
  • wordpress字段关联福州网站优化公司
  • 企业网站租服务器站长工具 站长之家
  • 网站建设教程赚找湖南岚鸿认 可用PS做网站搜索框
  • 推广农村特色产品建设网站方案网站栏目下拉菜单
  • asp.net旅游网站开发文档比百度好用的搜索引擎
  • 虚拟空间做网站网站搭建php源码
  • 万网网站备案证书网站地图提交给百度
  • 网站页面创意贸易公司网址大全
  • 网站制作时如何分析竞争对手wordpress 分类 文章数量
  • 搭建发卡网站要多少钱公司名字大全三个字
  • 做几个网站好微信怎么弄小程序卖东西
  • 河曲县城乡建设管理局网站建设一个网站 需要提供什么
  • 网站建设与管理就业做货代网站
  • 最低网网站多少钱免费搭建网站 域名
  • git怎么做隐私政策网站灯箱网站开发
  • 郑州市建设教育协会网站公司如何做网站推广
  • 网站seo步骤网站设计制作的公司
  • 菏泽企业网站建设网站头部seo范例