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

建设培训网站360推广官网

建设培训网站,360推广官网,宽带办理需要多少钱,私人可以有官方网址吗目录 1、双向带头循环链表的介绍 2、双向带头循环链表的接口 3、接口实现 3.1 开辟结点 3.2 创建返回链表的头结点 3.3 判断链表是否为空 3.4 打印 3.5 双向链表查找 3.6 双向链表在pos的前面进行插入 3.6.1 头插 3.6.2 尾插 3.6.3 更新头插、尾插写法 3.7 双向链…

目录

1、双向带头循环链表的介绍

2、双向带头循环链表的接口

3、接口实现

3.1 开辟结点

3.2 创建返回链表的头结点

3.3 判断链表是否为空

3.4 打印

3.5 双向链表查找

3.6 双向链表在pos的前面进行插入

3.6.1 头插

3.6.2 尾插

3.6.3 更新头插、尾插写法

3.7 双向链表删除pos位置的节点

3.7.1 头删

3.7.2 尾删

3.7.3 更新头删、尾删写法

3.8 双向链表销毁

4、完整代码

5、功能测试


1、双向带头循环链表的介绍

我们将这个题目拆分开来可以提取三个关键字:双向,带头,循环。我们就以这三个关键字来展开介绍一下:

首先是双向:双向就说明了这个结点可以找到自己的前驱和后继,这一点与单链表存在本质的区别;

其次是带头:带头说明链表有一个头结点,这个头结点也可以称为哨兵位的头结点,此结点与其他结点是一样的,只是它的 data 域放的是随机值(有的会存放链表的长度);

最后是循环:循环说明了它的结构是一个环装,头结点的前驱结点存放着尾结点,尾结点的后继结点存放着头结点。

2、双向带头循环链表的接口

双向带头循环链表与单链表的功能是一样的,都是可以增删查改的,但是双向带头循环链表的特性让这么功能写的时候大大提高了我们的效率。

// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}ListNode;// 创建返回链表的头结点
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);

3、接口实现

3.1 开辟结点

我们的链表是动态的链表,因此每次在插入的时候我们都需要 malloc 一个结点,我们将其封装成一个函数,方便后面的代码复用。

ListNode* BuyListNode(LTDataType x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (NULL == newnode){perror("malloc fail:");return NULL;}newnode->data = x;newnode->next = NULL;newnode->prev = NULL;return newnode;
}

3.2 创建返回链表的头结点

这一步是我们给链表创建一个哨兵位的头结点。因为是双向带头循环链表,因此我们让 prev 和 next 指针都指向自己,这样就算是只有一个头结点,我们也是双向循环的结构。

ListNode* ListCreate()
{ListNode* phead = BuyListNode(-1);phead->next = phead;phead->prev = phead;return phead;
}

3.3 判断链表是否为空

这一步是我们为后面的删除时封装的一个判空功能函数,当链表存在的时候不排除链表为空的情况,因此我们封装此函数,以便后面的接口复用。

bool ListEmpty(ListNode* pHead)
{assert(pHead);return pHead->next == pHead;
}

3.4 打印

打印函数我们已经很熟悉了,但是双向带头循环链表的打印终止条件要注意,这里不再是以前的 cur == NULL,而是 cur != pHead ,当 cur 走到 pHead 时就说明我们已经遍历完整个链表了。

void ListPrint(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->next;printf("guard");while (cur != pHead){printf("<==>%d", cur->data);cur = cur->next;}printf("<==>\n");
}

3.5 双向链表查找

查找不难,但是这里要注意,双向带头链表的第一个结点是哨兵位结点,因此我们要从哨兵位的下一个结点开始遍历查找(cur = pHead->next),循环的终止条件依然是 cur != pHead。

ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* cur = pHead->next;while (cur != pHead){if (cur->data == x)return cur;cur = cur->next;}return NULL;
}

3.6 双向链表在pos的前面进行插入

我们在找到pos位置后,在 pos 位置前进行插入,我们按下面的流程执行:

1、假如我们要在 data3 前插入一个 data4,我们先用定义一个结构体指针变量 prev,先将data3->prev (data2)结点保存在 prev 变量中;

2、再将 prev->next 改为 data4 ,然后将 data4->prev 改为 prev;

3、最后把 data4->next = data3,再把 data3->prev = data4。

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

3.6.1 头插

头插的话我们与在pos位置前插入一致,先将第一个结点保存起来,然后进行插入。

void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newnode = BuyListNode(x);ListNode* first = pHead->next;//多写这一个变量下面的插入语句就可以无序写pHead->next = newnode;newnode->next = first;newnode->prev = pHead;first->prev = newnode;
}

3.6.2 尾插

尾插的话先将链表的尾结点保存起来,然后进行插入,还是与在pos位置前插入一样。

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

3.6.3 更新头插、尾插写法

对比插入代码我们其实不难发现,头插、尾插与在pos位置前插入的代码逻辑是一样的,实现的功能根本上也没有变,那我们就在头插、尾插时直接复用 ListInsert 接口就可以实现。

1> 头插

void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListInsert(pHead->next, x);
}

2> 尾插

因为是 pos 位置前插入,链表是双向循环的,所以传的第一个参数就是 pHead ,哨兵位结点前一个结点就是尾结点。

void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListInsert(pHead, x);
}

3.7 双向链表删除pos位置的节点

我们在找到 pos 结点后,再将 pos 结点删除,我们按下面的流程执行:

1、定义两个结构体指针变量 posPrev与posNext,将 pos 位置前后结点分别保存在 posPrev与posNext 指针变量中;

2、将posPrev->next = posNext,再将 posNext->prev = posPrev;

3、释放掉 pos 结点,free(pos)。

void ListErase(ListNode* pos)
{assert(pos);ListNode* posPrev = pos->prev;ListNode* posNext = pos->next;posPrev->next = posNext;posNext->prev = posPrev;free(pos);
}

3.7.1 头删

头删的话我们先将 pHead->next结点与pHead->next->next结点保存下来,将哨兵位结点与头结点的下一个结点连接起来,再将头结点释放掉。

void ListPopFront(ListNode* pHead)
{assert(pHead);assert(!ListEmpty(pHead));ListNode* first = pHead->next;ListNode* second = first->next;pHead->next = second;first->prev = pHead;free(first);
}

3.7.2 尾删

尾删的话我们先将 pHead->prev结点与pHead->prev->prev结点保存下来,将哨兵位结点与尾结点的前一个结点连接起来,再将尾结点释放掉。

void ListPopBack(ListNode* pHead)
{assert(pHead);assert(!ListEmpty(pHead));ListNode* tail = pHead->prev;ListNode* tailPrev = tail->prev;tailPrev->next = pHead;pHead->prev = tailPrev;free(tail);
}

总结在头删与尾删前要判断链表是否为空。

3.7.3 更新头删、尾删写法

对比删除代码我们其实不难发现,头删、尾删与删除pos位置结点的代码逻辑是一样的,实现的功能根本上也没有变,那我们就在头删、尾删时直接复用 ListErase 接口就可以实现。

1> 头删

void ListPopFront(ListNode* pHead)
{assert(pHead);assert(!ListEmpty(pHead));ListErase(pHead->next);
}

2> 尾删

void ListPopBack(ListNode* pHead)
{assert(pHead);assert(!ListEmpty(pHead));ListErase(pHead->prev);
}

3.8 双向链表销毁

链表的销毁主要是遍历一遍链表,从 cur = pHead->next 开始,循环终止的条件为 cur != pHead,遍历完再将哨兵位结点释放掉,整个链表就被释放掉了。

void ListDestory(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->next;while (cur != pHead){ListNode* next = cur->next;free(cur);cur = next;}free(pHead);
}

4、完整代码

完整代码在代码仓库,入口:C语言: C语言学习的代码,多复习 - Gitee.com

5、功能测试

http://www.jinmujx.cn/news/115824.html

相关文章:

  • 设计师浏览网站新闻发布
  • 嘉盛集团官方网站免费网站排名优化在线
  • 河南官网网站建设怎么在百度发布自己的文章
  • 保定seo全网营销网站优化推广费用
  • phpwind做的网站优化设计单元测试卷答案
  • 怎么做联盟网站网上推广企业
  • wordpress适合做什么安卓优化大师app
  • 做微商怎样加入网站卖东西赚钱泉州百度开户
  • 自己做网站怎么做的网络营销推广合作
  • 网站开发与硬件合同公司网站
  • 地方门户网站的发展湖南好搜公司seo
  • 网站建设机构培训新产品的推广销售方法
  • 诸暨做网站广告的电话网站营销网
  • 做网站的公司cnfg新手seo入门教程
  • 网站制作里面链接怎么做淘宝付费推广有几种方式
  • 科技公司官网设计百度seo关键词外包
  • 乌鲁木齐网站开发优化设计七年级上册语文答案
  • 蜜芽免费网站域名怎么做网络推广最有效
  • 响应式网站管理西安疫情最新消息
  • 查内部券的网站是怎么做的百度95099如何转人工
  • 社保网站做的真烂深圳市住房和建设局
  • 太原做网站网站设计公司网站制作
  • 站长推荐自动跳转导航入口北京网站建设制作开发
  • 怎样在淘宝网做网站google海外推广
  • 南阳做网站的公司西安seo代运营
  • 广州网站建设360元360指数
  • 专业做网站团队结构优化
  • 优秀网站作品下载营销方案策划
  • 手机网站导航栏如何做磁力宅
  • 网站是专门对生活中的一些所谓常识做辟谣的宁波seo优化流程