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

搭建网站 软件长沙网站建设软件

搭建网站 软件,长沙网站建设软件,长沙有哪些做的好一点的网站,佛山 做网站一、链表的分类01 链表的分类① 单向或双向② 带头结点或不带头结点③ 循环或非循环02 常用的链表根据上面的分类我们可以细分出8种不同类型的链表,这么多链表我们一个个讲解这并没有意义。我们实际中最常用的链表是 "无头单向非循环链表" 和 "带头双…

一、链表的分类

01 链表的分类

① 单向或双向

② 带头结点或不带头结点

③ 循环或非循环

02 常用的链表

根据上面的分类我们可以细分出8种不同类型的链表,这么多链表我们一个个讲解这并没有意义。我们实际中最常用的链表是 "无头单向非循环链表" 和 "带头双向循环链表" ,至于 "无头单项非循环链表" 我们在上一章已经讲述过了,我们下面将讲解 "带头双向循环列表" 

解读:

① 无头单向非循环链表:结构简单,一般不会单独用来存储数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等。

② 带头双向循环链表:结构最复杂,但是实现反而简单。一般用来单独存储数据,实际中使用的链表数据结构都是带头双向链表。另外,这个结构虽然结构复杂,但是使用代码实现后会发现结构会带来很多优势。双向链表严格来说只需要快速的实现两个接口,insert 和 earse 头尾的插入和删除就可以搞定了,这就是结构的优势。

二、双向循环链表的定义

01 定义双向循环链表

typedef int DListNodeDataType;typedef struct DoubleListNode {DListNodeDataType data;struct DoubleListNode* prev;	// 前驱结点指针struct DoubleListNode* next;	// 后继结点指针
}DListNode;

02 接口函数

// 初始化
DListNode* DListInit();
// 创建新结点
DListNode* CreateNewNode(DListNodeDataType x);
// 打印
void DListPrint(DListNode* pHead);
// 尾插
void DListPushBack(DListNode* pHead, DListNodeDataType x);
// 头插
void DListPushFront(DListNode* pHead, DListNodeDataType x);
// 尾删
void DListPopBack(DListNode* pHead);
// 头删
void DListPopFront(DListNode* pHead);
// 查找
DListNode* DListFind(DListNode* pHead, DListNodeDataType x);
// 在 pos 位置之前插入
void DListInsert(DListNode* pos, DListNodeDataType x);
// 删除 pos 位置的结点
void DListEarse(DListNode* pos);

三、接口函数的实现

01 初始化(DListInit)

DList.h:

// 初始化
DListNode* DListInit();

DList.c:

/* 初始化 */
DListNode* DListInit() {// 哨兵位头结点DListNode* pHead = (DListNode*)malloc(sizeof(DListNode));pHead->next = pHead;pHead->prev = pHead;return pHead;
}

02 打印(DListPrint)

DList.h:

// 打印
void DListPrint(DListNode* pHead);

DList.c:

/* 打印 */
void DListPrint(DListNode* pHead) {assert(pHead != NULL);DListNode* cur = pHead->next;while (cur != pHead) {printf("%d ", cur->data);cur = cur->next;}printf("\n");
}

03 创建新结点(CreateNewNode)

创建新节点要经常用,为了方便复用,根据经验我们先把 CreateNewNode 写好:

/* 创建新结点 */
DListNode* CreateNewNode(DListNodeDataType x) {DListNode* new_node = (DListNode*)malloc(sizeof(DListNode));if (new_node == NULL) {printf("malloc failed");exit(-1);}new_node->data = x;new_node->next = NULL;new_node->prev = NULL;return new_node;
}

04 尾插(DListPushBack)

DList.h:

// 尾插
void DListPushBack(DListNode* pHead, DListNodeDataType x);

因为不用改变 pList,所以不需要使用二级指针。

DList.c:

/* 尾插 */
void DListPushBack(DListNode* pHead, DListNodeDataType x)
{assert(pHead != NULL);DListNode* tail = pHead->prev;DListNode* new_node = CreateNewNode(x);// pHead  tail  new_nodetail->next = new_node;new_node->prev = tail;pHead->prev = new_node;new_node->next = pHead;
}

 解读:

① 首先防止 pHead 为空。

② 因为要实现尾插,我们要找出尾部节点。我们这里并不需要像之前学单链表时需要创建寻尾指针找到尾部节点,直接用 pHead->prev 就可以了。是不是非常的方便?随后创建新节点,直接调用我们刚才写的  CreateNewNode 接口即可。

③ 实现尾插操作,画出来可以更好地写出代码。在注释里写一个简单地思路草图也是可以的,只要画好他们之间的链接关系,再写代码会变得非常简单:

思路草图: pHead   tail   new_node(尾插目标) 

然后再根据尾插的思路,我们就可以轻松写出代码了。

Test.c:

#include "DList.h"void TestList1() 
{DListNode* pList = DListInit();DListPushBack(pList, 1);DListPushBack(pList, 2);DListPushBack(pList, 3);DListPushBack(pList, 4);DListPrint(pList);
}int main() 
{TestList1();return 0;
}

运行结果如下:

05 头插(DListPushFront)

DList.h:

// 头插
void DListPushFront(DListNode* pHead, DListNodeDataType x);

解读:双向链表头插,即在第一个数据前面,也就是哨兵位和第一个数据之间插入一个数据。

DList.c:

/* 头插 */
void DListPushFront(DListNode* pHead, DListNodeDataType x)
{assert(pHead != NULL);DListNode* new_node = CreateNewNode(x);DListNode* pHeadNext = pHead->next;// pHead new_node pHeadNextpHead->next = new_node;new_node->next = pHeadNext;new_node->prev = pHead;pHeadNext->prev = new_node;
}

解读:

① 首先防止 pHead 为空。

② 既然是插入,那就创建新节点。双向链表头插,我们要找到第一个节点,通过 pHead->next 就可以拿到了,我们将它取名为 pHeadNext(表示第一个节点)。在哨兵位和第一个数据之间插入数据,画出草图就是:

思路草图: pHead  new_node(头插目标)  pHeadnext

根据草图我们开始写代码,将他们互相链接起来即可!

Test.c:

void TestList2()
{DListNode* pList = DListInit();DListPushFront(pList, 1);DListPushFront(pList, 2);DListPushFront(pList, 3);DListPushFront(pList, 4);DListPrint(pList);
}

运行结果如下:

06 尾删(DListPopBack)

DList.h:

// 尾删
void DListPopBack(DListNode* pHead);

DList.c:

/* 尾删 */
void DListPopBack(DListNode* pHead)
{assert(pHead != NULL);assert(pHead->next != pHead);// pHead tailPrev tailDListNode* tail = pHead->prev;DListNode* tailPrev = tail->prev;free(tail);tailPrev->next = pHead;pHead->prev = tailPrev;
}

解读:

① 首先防止 pHead 为空,这里还要预防下哨兵位被不小心干掉的情况,哨兵位指向自己就说明链表为空,链表为空就不能再继续删除了,断言 pHead->next == pHead 就可以了。

② 因为是尾删,我们要把尾部指针和它的前驱指针标出来。我们来画一下思路草图:

思路草图: pHead   tailPrev  tail(待删目标)

另外,这里使用前驱指针是为了避免 free 掉之后就没法链接了。

我们有了 tailPrev 了,所以我们先 free 掉 tail 也关系,此时 tail 已经被释放掉了,再进行链接就可以了。

Test.c:

void TestList3()
{DListNode* pList = DListInit();DListPushFront(pList, 1);DListPushFront(pList, 2);DListPushFront(pList, 3);DListPushFront(pList, 4);DListPrint(pList);DListPopBack(pList);DListPrint(pList);
}

运行结果如下:

07 头删(DListPopFront)

DList.h:

// 头删
void DListPopFront(DListNode* pHead);

DList.c:

/* 头删 */
void DListPopFront(DListNode* pHead)
{assert(pHead != NULL);assert(pHead->next != pHead);// pHead pHeadNext pHeadNextNextDListNode* pHeadNext = pHead->next;DListNode* pHeadNextNext = pHeadNext->next;pHead->next = pHeadNextNext;pHeadNextNext->prev = pHead;free(pHeadNext);
}

Test.c:

void TestList4()
{DListNode* pList = DListInit();DListPushFront(pList, 1);DListPushFront(pList, 2);DListPushFront(pList, 3);DListPushFront(pList, 4);DListPrint(pList);DListPopFront(pList);DListPrint(pList);
}

运行结果如下:

08 查找(DListFind)

DList.h:

// 查找
DListNode* DListFind(DListNode* pHead, DListNodeDataType x);

DList.c:

/* 查找 */
DListNode* DListFind(DListNode* pHead, DListNodeDataType x)
{assert(pHead);DListNode* cur = pHead->next;while (cur != pHead) {if (cur->data == x)return cur;cur = cur->next;}return NULL;
}

解读:很简单,和打印的思路一样。只需要创建一个 cur 从第一个有效节点(pHead->next)开始遍历链表就可以了。如果 cur->data 和传入的 x,即需要查找的值相同就返回 curcur 是带有值和地址的。如果整个链表都走完了还没有找到相同的值,就返回 NULL 。

09 在 pos 位置之前插入(DListInsert)

DList.h:

// 在 pos 位置之前插入
void DListInsert(DListNode* pos, DListNodeDataType x);

DList.c:

/* 在 pos 位置之前插入 */
void DListInsert(DListNode* pos, DListNodeDataType x)
{assert(pos != NULL);DListNode* new_node = CreateNewNode(x);DListNode* posPrev = pos->prev;// posPrev new_node posposPrev->next = new_node;new_node->prev = posPrev;new_node->next = pos;pos->prev = new_node;
}

解读:

① 防止 pos 传入为空。

② 首先创建新节点。因为是在 pos 位置之前插入,为了方便,我们先标出 pos 的前驱指针 posPrev,随后我们画出草图:

思路草图:posPrev  newnode(待插目标)   pos

此时,DListInsert 就大功告成了!它就是双向链表最核心的两个接口之一,我们可以将这个万能的 "pos位置之前插入" 复用到我们刚才写的尾插和头插,即 DListPushBack 和 DListPushFront 中:

/* 尾插 */
void DListPushBack(DListNode* pHead, DListNodeDataType x)
{assert(pHead != NULL);//DListNode* tail = pHead->prev;//DListNode* new_node = CreateNewNode(x);//// pHead  tail  new_node//tail->next = new_node;//new_node->prev = tail;//pHead->prev = new_node;//new_node->next = pHead;DListInsert(pHead, x);
}
/* 头插 */
void DListPushFront(DListNode* pHead, DListNodeDataType x)
{assert(pHead != NULL);//DListNode* new_node = CreateNewNode(x);//DListNode* pHeadNext = pHead->next;//// pHead new_node pHeadNext//pHead->next = new_node;//new_node->next = pHeadNext;//new_node->prev = pHead;//pHeadNext->prev = new_node;DListInsert(pHead->next, x);
}

10 删除 pos 位置的结点(DListErase)

DList.h:

// 删除 pos 位置的结点
void DListEarse(DListNode* pos);

DList.c:

/* 删除 pos 位置的结点 */
void DListErase(DListNode* pos)
{assert(pos != NULL); DListNode* posPrev = pos->prev; DListNode* posNext = pos->next; // posPrev  pos  posNextposPrev->next = posNext;posNext->prev = posPrev;free(pos);pos = NULL;
}

解读:

① 防止 pos 传入为空。

② 既然要删除 pos 位置的节点,我们先标出 pos 的前驱指针 posPrev 和 pos 的后继指针 posNext ,随后我们画出草图:

思路草图: posPrev  pos  posNext

此时,DListErase 也搞定了!我们可以将这个万能的 "pos位置删除" 复用到之前写的尾删和头删那里,即 DListPopBack 和 DListPopFront 中:

/* 尾删 */
void DListPopBack(DListNode* pHead)
{assert(pHead != NULL);assert(pHead->next != pHead);//// pHead tailPrev tail//DListNode* tail = pHead->prev;//DListNode* tailPrev = tail->prev;//free(tail);//tailPrev->next = pHead;//pHead->prev = tailPrev;DListErase(pHead->prev);
}
/* 头删 */
void DListPopFront(DListNode* pHead)
{assert(pHead != NULL);assert(pHead->next != pHead);//// pHead pHeadNext pHeadNextNext//DListNode* pHeadNext = pHead->next;//DListNode* pHeadNextNext = pHeadNext->next;//pHead->next = pHeadNextNext;//pHeadNextNext->prev = pHead;//free(pHeadNext);DListErase(pHead->next);
}

四、完整代码

DList.h:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int DListNodeDataType;typedef struct DoubleListNode {DListNodeDataType data;struct DoubleListNode* prev;	// 前驱结点指针struct DoubleListNode* next;	// 后继结点指针
}DListNode;// 初始化
DListNode* DListInit();
// 创建新结点
DListNode* CreateNewNode(DListNodeDataType x);
// 打印
void DListPrint(DListNode* pHead);
// 尾插
void DListPushBack(DListNode* pHead, DListNodeDataType x);
// 头插
void DListPushFront(DListNode* pHead, DListNodeDataType x);
// 尾删
void DListPopBack(DListNode* pHead);
// 头删
void DListPopFront(DListNode* pHead);
// 查找
DListNode* DListFind(DListNode* pHead, DListNodeDataType x);
// 在 pos 位置之前插入
void DListInsert(DListNode* pos, DListNodeDataType x);
// 删除 pos 位置的结点
void DListErase(DListNode* pos);

DList.c:

#include "DList.h"/* 初始化 */
DListNode* DListInit() {// 哨兵位头结点DListNode* pHead = (DListNode*)malloc(sizeof(DListNode));pHead->next = pHead;pHead->prev = pHead;return pHead;
}/* 打印 */
void DListPrint(DListNode* pHead) {assert(pHead != NULL);DListNode* cur = pHead->next;while (cur != pHead) {printf("%d ", cur->data);cur = cur->next;}printf("\n");
}/* 创建新结点 */
DListNode* CreateNewNode(DListNodeDataType x) {DListNode* new_node = (DListNode*)malloc(sizeof(DListNode));if (new_node == NULL) {printf("malloc failed");exit(-1);}new_node->data = x;new_node->next = NULL;new_node->prev = NULL;return new_node;
}/* 尾插 */
void DListPushBack(DListNode* pHead, DListNodeDataType x)
{assert(pHead != NULL);//DListNode* tail = pHead->prev;//DListNode* new_node = CreateNewNode(x);//// pHead  tail  new_node//tail->next = new_node;//new_node->prev = tail;//pHead->prev = new_node;//new_node->next = pHead;DListInsert(pHead, x);
}/* 头插 */
void DListPushFront(DListNode* pHead, DListNodeDataType x)
{assert(pHead != NULL);//DListNode* new_node = CreateNewNode(x);//DListNode* pHeadNext = pHead->next;//// pHead new_node pHeadNext//pHead->next = new_node;//new_node->next = pHeadNext;//new_node->prev = pHead;//pHeadNext->prev = new_node;DListInsert(pHead->next, x);
}/* 尾删 */
void DListPopBack(DListNode* pHead)
{assert(pHead != NULL);assert(pHead->next != pHead);//// pHead tailPrev tail//DListNode* tail = pHead->prev;//DListNode* tailPrev = tail->prev;//free(tail);//tailPrev->next = pHead;//pHead->prev = tailPrev;DListErase(pHead->prev);
}/* 头删 */
void DListPopFront(DListNode* pHead)
{assert(pHead != NULL);assert(pHead->next != pHead);//// pHead pHeadNext pHeadNextNext//DListNode* pHeadNext = pHead->next;//DListNode* pHeadNextNext = pHeadNext->next;//pHead->next = pHeadNextNext;//pHeadNextNext->prev = pHead;//free(pHeadNext);DListErase(pHead->next);
}/* 查找 */
DListNode* DListFind(DListNode* pHead, DListNodeDataType x)
{assert(pHead);DListNode* cur = pHead->next;while (cur != pHead) {if (cur->data == x)return cur;cur = cur->next;}return NULL;
}/* 在 pos 位置之前插入 */
void DListInsert(DListNode* pos, DListNodeDataType x)
{assert(pos != NULL);DListNode* new_node = CreateNewNode(x);DListNode* posPrev = pos->prev;// posPrev new_node posposPrev->next = new_node;new_node->prev = posPrev;new_node->next = pos;pos->prev = new_node;
}/* 删除 pos 位置的结点 */
void DListErase(DListNode* pos)
{assert(pos != NULL); DListNode* posPrev = pos->prev; DListNode* posNext = pos->next; // posPrev  pos  posNextposPrev->next = posNext;posNext->prev = posPrev;free(pos);pos = NULL;
}
http://www.dtcms.com/a/502550.html

相关文章:

  • 微擎 网站开发工具wordpress修改文章浏览次数
  • 秦皇岛网站制作人才招聘公司网络营销
  • 丈哥seo博客工具杭州seo招聘
  • 做网站和做app那个简单工作室网站需要备案吗
  • 网站平台建设投资费用清单女装网站模板
  • 路由器带u盘接口的做网站软件制作流程
  • 网站名是什么dw超链接自己做的网站
  • 怎么样给一个网站做自然排名网站开发交易
  • 天津网站开发建设公司做网站不用tomcat行吗
  • 纯免费建站做情侣网站
  • 织梦网站版本济南百度推广开户
  • 网站建设交流平台网站开发的需求分析书
  • 国外企业网站怎么做临漳网站建设
  • 网站建设网站定制一级a做爰片免播放器网站
  • 菜鸟是什么网站商城网站建站系统
  • 装饰公司网站php源码网站建设费进项税金可以抵扣吗
  • 东莞网站关键排名北京网页设计师培训多少钱
  • 北京网站名称注册证书社保在哪个网站做增员
  • 建设中专网站深圳网站程序开发
  • 拼多多网站开发wordpress index.php on line 17
  • 中卫市建设局网站网站建设个网站一般需要花多少钱
  • 北京企业建网站优帮云微信运营网站建设
  • 西安学校网站建设价格网站建设金手指霸屏
  • 上海做推广网站亚马逊站外推广怎么做
  • 网站建设黄页免费在线观看wordpress伪静态htaccess
  • 最新舆情信息范文seog
  • 上海 建站广东嵘通建设
  • 北京手机模板建站聊天app搭建
  • 购物网站怎么建立wordpress前台文章
  • 网站软文代写凡客生活官网