首页 > 其他分享 >常用数据结构:单向链表和双向链表的实现

常用数据结构:单向链表和双向链表的实现

时间:2022-12-19 20:31:20浏览次数:47  
标签:weight 单向 链表 pf printf 数据结构 LinkNode 节点


常用数据结构:单向链表和双向链表的实现_链表

1、链表是什么?

链表是编程语言中常见的一种数据结构,它可以实现动态的创建和删除,只要内存足够,链表的数量和长度是可以无限多和无限长的。

链表顾名思义是一种链式的数据结构,它由一个个节点组成,并通过节点之间的互相关联链接,形成了类似一条链式的结构。

链表的节点一般可以分为数据域和指针域。数据域中是存放节点数据的,往往链表的节点都是结构体类型的,可以方便定义多种不同的数据类型,便于使用。指针域是存放节点的指针的,是链表中每个节点能互相串联起来的关键,这个至关重要!

一个链表节点的示意图如下:

常用数据结构:单向链表和双向链表的实现_链表_02

2、 单向链表

2.1、单向不循环链表

单向不循环链表是一种单向的链式结构,节点之间通过指针域互相关联,最后一个节点的指针域为空(NULL)。如下图所示:

常用数据结构:单向链表和双向链表的实现_链表_03

下面用C语言实现一个单向不循环链表的代码。

(1)  先定义一个链表的节点。如下:

// 定义一个链表节点的数据域。以记录一个苹果的信息为例,为方便说明,假设每个苹果的信息各不相同
typedef struct LinkData_struct
{
int weight; // 苹果的重量
int hight; // 苹果的高度
// ... // 还可以定义更多的其他的数据
}LinkData_t;

/*** 定义一个链表节点 ******/
typedef struct LinkNode_Struct
{
LinkData_t data; // 链表节点的数据域
struct LinkNode_Struct *Next; // 链表节点的指针域
}LinkNode_t;

(2)  定义一个单向链表的头结点。如下:

/*** 定义一个单向链表的头结点 ***/
LinkNode_t AppleInfo_head; //作为单向链表的一个头结点

(3)  初始化单向链表。如下:

// 初始化单向链表的头结点
void Init_LinkNode(LinkNode_t * HeadNode)
{
HeadNode->Next = NULL;
}

(4)  创建链表节点并接入到链表中。如下:

// 创建一个链表节点并接入到链表中
LinkNode_t * LinkNode_Create(LinkNode_t * HeadNode, LinkData_t *InsetData)
{
LinkNode_t *Node,*pf;
LinkNode_t *xReturn = NULL;
Node = (LinkNode_t *)malloc(sizeof(LinkNode_t));

if (Node == NULL)
{
printf("节点创建失败!!!\r\n");
return NULL;
}

pf = HeadNode;
while(pf->Next != NULL)
{
pf = pf->Next;
}
pf->Next = Node;
Node->Next = NULL;
Node->data.hight = InsetData->hight;
Node->data.weight = InsetData->weight;
xReturn = Node;

printf("完成一个链表节点的创建,地址 = 0x%X\r\n",xReturn);
return xReturn;
}

(5)  删除链表中的节点。如下:

// 删除链表中的某个节点,根据weight进行删除
void destroy_LinkNode(LinkNode_t * HeadNode, int weight)
{
int deleteFlag = 0;
LinkNode_t *pf,*preStre;

pf = preStre = HeadNode;

do
{
if (pf->data.weight == weight){
deleteFlag = 1;
break;
}
preStre = pf;
pf = pf->Next;
}while (pf->Next != NULL);

if (!deleteFlag)
{
printf("找不到这个节点!!!\r\n");
}
else
{
if(pf->Next == NULL) // 该点是尾节点
{
preStre->Next = NULL;
}
else
{
preStre->Next = pf->Next;
}
free(pf);
printf("节点weight = %d 销毁成功!\r\n",weight);
}
}

(6)  输出整条链表的数据。如下:

// 输出显示整条链表
void print_LinkNode_Info(LinkNode_t * HeadNode)
{
int length = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == NULL)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("\r\n");
length++;
}while (pf->Next != NULL);
printf("链表输出完成。长度为:%d\r\n",length);
}

(7)  按条件查询链表中某个节点的数据。如下:

// 按条件查询链表中某个节点的数据
void search_LinkNode_Info(LinkNode_t * HeadNode, int weight)
{
int length = 0;
char search_flag = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == NULL)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
if(pf->data.weight == weight)
{
search_flag = 1;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("\r\n");
}
length++;
}while (pf->Next != NULL);

if(search_flag)
{
printf("链表查找结束。所在节点位置为:%d\r\n",length);
}
else
{
printf("整个链表中无满足此条件的节点!\r\n");
}
}

完整的demo如下:

注意:这个demo可以直接运行在控制台上输出显示!

void print_debug_info(void)
{
printf("******** 链表控制台 *****************\r\n");
printf("* \r\n");
printf("* 1:创建链表 \r\n");
printf("* 2:删除链表 \r\n");
printf("* 3:显示整条链表的数据 \r\n");
printf("* 4:按条件查找链表节点 \r\n");
printf("* 8:清空显示 \r\n");
printf("* 9:结束运行 \r\n");
printf("* \r\n");
printf("************************************\r\n");
}

int main(int argc, char *argv[])
{
int Num,i,j;
int Options;
int weight,height;
LinkData_t InsetData;

Init_LinkNode(&AppleInfo_head);

while (1)
{
print_debug_info();
printf("\r\n请输入需要操作的键值,按回车键确认!\r\n");
scanf("%d", &Options);
switch (Options)
{
case 1:
/*** 创建任意长度的链表 **********************************************************/
printf("请输入需要创建的链表节点的数量,按回车结束!\r\n");
scanf("%d", &Num);

printf("请输入节点的数据:\r\n");
for (i = 0; i < Num; i++)
{
printf("请输入第 %d 节点的数据,weight = Height = ,输入完毕按回车结束!\r\n",i+1);
scanf("%d %d", &weight,&height);
InsetData.weight = weight;
InsetData.hight = height;
printf("weight = %d height = %d\r\n",weight,height);

if(LinkNode_Create(&AppleInfo_head, &InsetData) > NULL)
{
printf("节点 %d 创建成功!\r\n\r\n\r\n",i+1);
}
else
{
printf("节点 %d 创建失败!\r\n\r\n\r\n",i+1);
}
}
printf("\r\n");
break;

case 2:
/******* 删除链表中的某个节点 ***************************************************/
printf("请输入需要删除的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
destroy_LinkNode(&AppleInfo_head, Num);
printf("\r\n");
break;

case 3:
printf("链表数据为:\r\n");
print_LinkNode_Info(&AppleInfo_head, Num);
printf("\r\n");
break;

case 4:
printf("请输入需要查找的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
search_LinkNode_Info(&AppleInfo_head, Num);
printf("\r\n");
break;

case 8:
system("cls");
break;

case 9:
printf("退出链表控制台,请再次运行程序!\r\n");
return;
break;

default:
printf("无效的键值,请重新输入!\r\n");
break;
}
}
return 0;
}


2.2、单向循环链表

单向循环链表是一种单向的可回头的链表,节点之间通过指针域互相关联,最后一个节点的指针域为头结点的地址。如下图所示:

常用数据结构:单向链表和双向链表的实现_链表_04

下面用C语言实现一个单向循环链表的代码。

(1)先定义一个链表的节点。如下:

// 定义一个链表节点的数据域。以记录一个苹果的信息为例,为方便说明,假设每个苹果的信息各不相同
typedef struct LinkData_struct
{
int weight; // 苹果的重量
int hight; // 苹果的高度
// ... // 还可以定义更多的其他的数据
}LinkData_t;

/*** 定义一个链表节点 ******/
typedef struct LinkNode_Struct
{
LinkData_t data; // 链表节点的数据域
struct LinkNode_Struct *Next; // 链表节点的指针域
}LinkNode_t;

(2)定义一个单向链表的头结点。如下:

/*** 定义一个单向链表的头结点 ***/
LinkNode_t AppleInfo_head; //作为单向链表的一个头结点

(3)初始化单向链表。如下:

// 初始化单向循环链表的头结点
void Init_LinkNode(LinkNode_t * HeadNode)
{
HeadNode->Next = HeadNode;
}

(4)创建链表节点并接入到链表中。如下:

// 创建一个链表节点并接入到单向循环链表中
LinkNode_t * LinkNode_Create(LinkNode_t * HeadNode, LinkData_t *InsetData)
{
LinkNode_t *Node,*pf;
LinkNode_t *xReturn = NULL;
Node = (LinkNode_t *)malloc(sizeof(LinkNode_t));

if (Node == NULL)
{
printf("节点创建失败!!!\r\n");
return NULL;
}

pf = HeadNode;
while(pf->Next != HeadNode)
{
pf = pf->Next;
}
pf->Next = Node;
Node->Next = HeadNode;
Node->data.hight = InsetData->hight;
Node->data.weight = InsetData->weight;
xReturn = Node;

printf("完成一个链表节点的创建,地址 = 0x%X\r\n",xReturn);
return xReturn;
}

(5)删除链表中的节点。如下:

// 删除链表中的某个节点,根据weight进行删除
void destroy_LinkNode(LinkNode_t * HeadNode, int weight)
{
int deleteFlag = 0;
LinkNode_t *pf,*preStre;

pf = preStre = HeadNode;

do
{
preStre = pf;
pf = pf->Next;
if (pf->data.weight == weight){
deleteFlag = 1;
break;
}
}while (pf->Next != HeadNode);

if (!deleteFlag)
{
printf("找不到这个节点!!!\r\n");
}
else
{
if(pf->Next == HeadNode) // 该点是尾节点
{
preStre->Next = HeadNode;
}
else
{
preStre->Next = pf->Next;
}
free(pf);
printf("节点weight = %d 销毁成功!\r\n",weight);
}
}

(6)输出整条链表的数据。如下:

// 输出显示整条链表
void print_LinkNode_Info(LinkNode_t * HeadNode)
{
int length = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == HeadNode)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("\r\n");
length++;
}while (pf->Next != HeadNode);
printf("链表输出完成。长度为:%d\r\n",length);
}

(7)按条件查询链表中某个节点的数据。如下:

// 按条件查询链表中某个节点的数据
void search_LinkNode_Info(LinkNode_t * HeadNode, int weight)
{
int length = 0;
char search_flag = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == HeadNode)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
if(pf->data.weight == weight)
{
search_flag = 1;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("\r\n");
}
length++;
}while (pf->Next != HeadNode);

if(search_flag)
{
printf("链表查找结束。所在节点位置为:%d\r\n",length);
}
else
{
printf("整个链表中无满足此条件的节点!\r\n");
}
}

完整的demo如下:

注意:这个demo可以直接运行在控制台上输出显示!

void print_debug_info(void)
{
printf("******** 链表控制台 *****************\r\n");
printf("* \r\n");
printf("* 1:创建链表 \r\n");
printf("* 2:删除链表 \r\n");
printf("* 3:显示整条链表的数据 \r\n");
printf("* 4:按条件查找链表节点 \r\n");
printf("* 8:清空显示 \r\n");
printf("* 9:结束运行 \r\n");
printf("* \r\n");
printf("************************************\r\n");
}

int main(int argc, char *argv[])
{
int Num,i,j;
int Options;
int weight,height;
LinkData_t InsetData;

Init_LinkNode(&AppleInfo_head);

while (1)
{
print_debug_info();
printf("\r\n请输入需要操作的键值,按回车键确认!\r\n");
scanf("%d", &Options);
switch (Options)
{
case 1:
/*** 创建任意长度的链表 **********************************************************/
printf("请输入需要创建的链表节点的数量,按回车结束!\r\n");
scanf("%d", &Num);

printf("请输入节点的数据:\r\n");
for (i = 0; i < Num; i++)
{
printf("请输入第 %d 节点的数据,weight = Height = ,输入完毕按回车结束!\r\n",i+1);
scanf("%d %d", &weight,&height);
InsetData.weight = weight;
InsetData.hight = height;
printf("weight = %d height = %d\r\n",weight,height);

if(LinkNode_Create(&AppleInfo_head, &InsetData) > NULL)
{
printf("节点 %d 创建成功!\r\n\r\n\r\n",i+1);
}
else
{
printf("节点 %d 创建失败!\r\n\r\n\r\n",i+1);
}
}
printf("\r\n");
break;

case 2:
/******* 删除链表中的某个节点 ***************************************************/
printf("请输入需要删除的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
destroy_LinkNode(&AppleInfo_head, Num);
printf("\r\n");
break;

case 3:
printf("链表数据为:\r\n");
print_LinkNode_Info(&AppleInfo_head, Num);
printf("\r\n");
break;

case 4:
printf("请输入需要查找的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
search_LinkNode_Info(&AppleInfo_head, Num);
printf("\r\n");
break;

case 8:
system("cls");
break;

case 9:
printf("退出链表控制台,请再次运行程序!\r\n");
return;
break;

default:
printf("无效的键值,请重新输入!\r\n");
break;
}
}
return 0;
}


3、双向链表

双向链表和单向链表相比,最大的不同是指针域中多了一个指向前一个节点的地址域。这样一来,双向链表中的每个节点就保存了前后节点的地址,从而通过地址形成一条链式的存储结构。

双向链表的最大便利之处在于查询链表时不仅可以正向查找也可以反向查找,甚至如果当前查询的位置在链表中间的位置的时候,可以反方向两头查找,提高查找的速度和效率,增加了便利。

双向链表也有循环和不循环两种方式,下面分别介绍。


3.1、双向不循环链表

双向不循环链表是头结点的前一个指针指向头结点自身,尾节点的后一个指针指向为NULL。示意图如下:

常用数据结构:单向链表和双向链表的实现_链表_05

双向不循环链表的代码实现如下示例:

#include <stdio.h>
#include <stdlib.h>


/*** 定义链表操作的位置:开头、中间、结尾 ***/
typedef enum
{
Head = 1,
Middle,
End,
}Location;


/*** 定义一个链表节点 ******/
// 1.定义一个链表节点的数据域。以记录一个苹果的信息为例,为方便说明,假设每个苹果的信息各不相同
typedef struct LinkData_struct
{
int weight; // 苹果的重量
int hight; // 苹果的高度
// ... // 还可以定义更多的其他的数据
}LinkData_t;

typedef struct LinkNode_Struct
{
LinkData_t data; // 链表节点的数据域
struct LinkNode_Struct *Prev; // 链表节点的上一个节点的指针域
struct LinkNode_Struct *Next; // 链表节点的下一个节点的指针域
}LinkNode_t;


/*** 定义一个单向链表的头结点 ***/
LinkNode_t AppleInfo_head; //作为单向链表的一个头结点


// 初始化单向链表的头结点
void Init_LinkNode(LinkNode_t * HeadNode)
{
HeadNode->Next = NULL;
HeadNode->Prev = NULL;
}

// 创建一个链表节点并接入到链表中
LinkNode_t * LinkNode_Create(LinkNode_t * HeadNode, LinkData_t *InsetData)
{
LinkNode_t *Prev_pf,*Next_pf;
LinkNode_t *xReturn = NULL;
LinkNode_t *Node = (LinkNode_t *)malloc(sizeof(LinkNode_t));

if (Node == NULL)
{
printf("节点创建失败!!!\r\n");
return NULL;
}

Prev_pf = Next_pf = HeadNode;

// 第一节点从头结点后面开始插入
if (HeadNode->Next == NULL && HeadNode->Prev == NULL)
{
HeadNode->Next = Node;
Node->Next = NULL;
Node->Prev = HeadNode;
Node->data.hight = InsetData->hight;
Node->data.weight = InsetData->weight;
xReturn = Node;
}
else
{
while (Next_pf->Next != NULL)
{
Next_pf = Next_pf->Next;
}
Next_pf->Next = Node;
Node->Prev = Next_pf;
Node->Next = NULL;
Node->data.hight = InsetData->hight;
Node->data.weight = InsetData->weight;
xReturn = Node;
}

printf("完成一个链表节点的创建,地址 = 0x%X\r\n",xReturn);
return xReturn;
}

// 删除链表中的某个节点,根据weight进行删除
void destroy_LinkNode(LinkNode_t * HeadNode, int weight)
{
int deleteFlag = 0;
LinkNode_t *pf;

pf = HeadNode;

do
{
pf = pf->Next;
if (pf->data.weight == weight)
{
deleteFlag = 1;
break;
}
}while (pf->Next != NULL);

if (!deleteFlag)
{
printf("链表中找不到这个节点!!!\r\n");
}
else
{
if (pf->Next == NULL)
{
pf->Prev->Next = NULL;
}
else
{
pf->Prev->Next = pf->Next;
pf->Next->Prev = pf->Prev;
}

free(pf);
printf("节点weight = %d 销毁成功!\r\n",weight);
}
}

// 输出显示整条链表
void print_LinkNode_Info(LinkNode_t * HeadNode)
{
int length = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == NULL)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("\r\n");
length++;
}while (pf->Next != NULL);
printf("链表输出完成。长度为:%d\r\n",length);
}


// 按条件查询链表中某个节点的数据
void search_LinkNode_Info(LinkNode_t * HeadNode, int weight)
{
int length = 0;
char search_flag = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == NULL)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
if(pf->data.weight == weight)
{
search_flag = 1;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("\r\n");
}
length++;
}while (pf->Next != NULL);

if(search_flag)
{
printf("链表查找结束。所在节点位置为:%d\r\n",length);
}
else
{
printf("整个链表中无满足此条件的节点!\r\n");
}
}

// 查询链表中有几个相同的数据
void search_Same_LinkNode_Info(LinkNode_t * HeadNode, int weight)
{
int length = 0,cnt = 0;
char search_flag = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == NULL)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
length++;
if(pf->data.weight == weight)
{
search_flag = 1;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("这个节点在链表中的位置:%d\r\n",length);
cnt++;
}
}while (pf->Next != NULL);

if(search_flag)
{
printf("链表查找结束。相同数据的节点数量为:%d\r\n",cnt);
}
else
{
printf("整个链表中无满足此条件的节点!\r\n");
}
}


void print_debug_info(void)
{
printf("******** 链表控制台 *****************\r\n");
printf("* \r\n");
printf("* 1:创建链表 \r\n");
printf("* 2:删除链表 \r\n");
printf("* 3:显示整条链表的数据 \r\n");
printf("* 4:按条件查找链表节点 \r\n");
printf("* 5:查找链表中有几个相同数据的节点 \r\n");
printf("* 8:清空显示 \r\n");
printf("* 9:结束运行 \r\n");
printf("* \r\n");
printf("************************************\r\n");
}


int main(int argc, char *argv[])
{
int Num,i,j;
int Options;
int weight,height;
LinkData_t InsetData;

Init_LinkNode(&AppleInfo_head);


while (1)
{
print_debug_info();
printf("\r\n请输入需要操作的键值,按回车键确认!\r\n");
scanf("%d", &Options);
switch (Options)
{
case 1:
/*** 创建任意长度的链表 **********************************************************/
printf("请输入需要创建的链表节点的数量,按回车结束!\r\n");
scanf("%d", &Num);

printf("请输入节点的数据:\r\n");
for (i = 0; i < Num; i++)
{
printf("请输入第 %d 节点的数据,weight = Height = ,输入完毕按回车结束!\r\n",i+1);
scanf("%d %d", &weight,&height);
InsetData.weight = weight;
InsetData.hight = height;
printf("weight = %d height = %d\r\n",weight,height);

if(LinkNode_Create(&AppleInfo_head, &InsetData) > NULL)
{
printf("节点 %d 创建成功!\r\n\r\n\r\n",i+1);
}
else
{
printf("节点 %d 创建失败!\r\n\r\n\r\n",i+1);
}
}
printf("\r\n");
break;

case 2:
/******* 删除链表中的某个节点 ***************************************************/
printf("请输入需要删除的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
destroy_LinkNode(&AppleInfo_head, Num);
printf("\r\n");
break;

case 3:
printf("链表数据为:\r\n");
print_LinkNode_Info(&AppleInfo_head);
printf("\r\n");
break;

case 4:
printf("请输入需要查找的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
search_LinkNode_Info(&AppleInfo_head, Num);
printf("\r\n");
break;

case 5:
printf("请输入需要查找的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
search_Same_LinkNode_Info(&AppleInfo_head, Num);
printf("\r\n");
break;

case 8:
system("cls");
break;

case 9:
printf("退出链表控制台,请再次运行程序!\r\n");
return;
break;

default:
printf("无效的键值,请重新输入!\r\n");
break;
}
}
return 0;
}


3.2、双向循环链表

双向循环链表是头结点的前一个指针指向尾结点的地址,尾节点的后一个指针指向头结点的地址所在,从而构成一种链式的循环结构。示意图如下:

常用数据结构:单向链表和双向链表的实现_链表_06

双向循环链表的示意代码如下:

#include <stdio.h>
#include <stdlib.h>


/*** 定义链表操作的位置:开头、中间、结尾 ***/
typedef enum
{
Head = 1,
Middle,
End,
}Location;


/*** 定义一个链表节点 ******/
// 1.定义一个链表节点的数据域。以记录一个苹果的信息为例,为方便说明,假设每个苹果的信息各不相同
typedef struct LinkData_struct
{
int weight; // 苹果的重量
int hight; // 苹果的高度
// ... // 还可以定义更多的其他的数据
}LinkData_t;

typedef struct LinkNode_Struct
{
LinkData_t data; // 链表节点的数据域
struct LinkNode_Struct *Prev; // 链表节点的上一个节点的指针域
struct LinkNode_Struct *Next; // 链表节点的下一个节点的指针域
}LinkNode_t;


/*** 定义一个单向链表的头结点 ***/
LinkNode_t AppleInfo_head; //作为单向链表的一个头结点


// 初始化单向链表的头结点
void Init_LinkNode(LinkNode_t * HeadNode)
{
HeadNode->Next = NULL;
HeadNode->Prev = HeadNode; // 双向循环链表的头结点的前一个指针指向头结点本身
}

// 创建一个链表节点并接入到链表中
LinkNode_t * LinkNode_Create(LinkNode_t * HeadNode, LinkData_t *InsetData)
{
LinkNode_t *Prev_pf,*Next_pf;
LinkNode_t *xReturn = NULL;
LinkNode_t *Node = (LinkNode_t *)malloc(sizeof(LinkNode_t));

if (Node == NULL)
{
printf("节点创建失败!!!\r\n");
return NULL;
}

Prev_pf = Next_pf = HeadNode;

// 第一节点从头结点后面开始插入
if (HeadNode->Next == NULL && HeadNode->Prev == HeadNode)
{
HeadNode->Next = Node;
HeadNode->Prev = Node;
Node->Next = HeadNode;
Node->Prev = HeadNode;
Node->data.hight = InsetData->hight;
Node->data.weight = InsetData->weight;
xReturn = Node;
}
else
{
while (Next_pf->Next != HeadNode)
{
Next_pf = Next_pf->Next;
}
Next_pf->Next = Node;
HeadNode->Prev = Node;
Node->Prev = Next_pf;
Node->Next = HeadNode;
Node->data.hight = InsetData->hight;
Node->data.weight = InsetData->weight;
xReturn = Node;
}

printf("完成一个链表节点的创建,地址 = 0x%X\r\n",xReturn);
return xReturn;
}

// 删除链表中的某个节点,根据weight进行删除
void destroy_LinkNode(LinkNode_t * HeadNode, int weight)
{
int deleteFlag = 0;
LinkNode_t *pf;

pf = HeadNode;

do
{
pf = pf->Next;
if (pf->data.weight == weight)
{
deleteFlag = 1;
break;
}
}while (pf->Next != HeadNode);

if (!deleteFlag)
{
printf("链表中找不到这个节点!!!\r\n");
}
else
{
if (pf->Next == HeadNode)
{
pf->Prev->Next = HeadNode;
HeadNode->Prev = pf;
}
else
{
pf->Prev->Next = pf->Next;
pf->Next->Prev = pf->Prev;
}

free(pf);
printf("节点weight = %d 销毁成功!\r\n",weight);
}
}

// 输出显示整条链表
void print_LinkNode_Info(LinkNode_t * HeadNode)
{
int length = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == NULL)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("\r\n");
length++;
}while (pf->Next != HeadNode);
printf("链表输出完成。长度为:%d\r\n",length);
}


// 按条件查询链表中某个节点的数据
void search_LinkNode_Info(LinkNode_t * HeadNode, int weight)
{
int length = 0;
char search_flag = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == NULL)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
if(pf->data.weight == weight)
{
search_flag = 1;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("\r\n");
}
length++;
}while (pf->Next != HeadNode);

if(search_flag)
{
printf("链表查找结束。所在节点位置为:%d\r\n",length);
}
else
{
printf("整个链表中无满足此条件的节点!\r\n");
}
}

// 查询链表中有几个相同的数据
void search_Same_LinkNode_Info(LinkNode_t * HeadNode, int weight)
{
int length = 0,cnt = 0;
char search_flag = 0;
LinkNode_t *pf = HeadNode;

if (pf->Next == NULL)
{
printf("该链表长度为零,不能输出结果!\r\n");
return;
}

do
{
pf = pf->Next;
length++;
if(pf->data.weight == weight)
{
search_flag = 1;
printf("weight = %d\r\n", (int)pf->data.weight);
printf("height = %d\r\n", (int)pf->data.hight);
printf("这个节点在链表中的位置:%d\r\n",length);
cnt++;
}
}while (pf->Next != HeadNode);

if(search_flag)
{
printf("链表查找结束。相同数据的节点数量为:%d\r\n",cnt);
}
else
{
printf("整个链表中无满足此条件的节点!\r\n");
}
}


void print_debug_info(void)
{
printf("******** 链表控制台 *****************\r\n");
printf("* \r\n");
printf("* 1:创建链表 \r\n");
printf("* 2:删除链表 \r\n");
printf("* 3:显示整条链表的数据 \r\n");
printf("* 4:按条件查找链表节点 \r\n");
printf("* 5:查找链表中有几个相同数据的节点 \r\n");
printf("* 8:清空显示 \r\n");
printf("* 9:结束运行 \r\n");
printf("* \r\n");
printf("************************************\r\n");
}


int main(int argc, char *argv[])
{
int Num,i,j;
int Options;
int weight,height;
LinkData_t InsetData;

Init_LinkNode(&AppleInfo_head);


while (1)
{
print_debug_info();
printf("\r\n请输入需要操作的键值,按回车键确认!\r\n");
scanf("%d", &Options);
switch (Options)
{
case 1:
/*** 创建任意长度的链表 **********************************************************/
printf("请输入需要创建的链表节点的数量,按回车结束!\r\n");
scanf("%d", &Num);

printf("请输入节点的数据:\r\n");
for (i = 0; i < Num; i++)
{
printf("请输入第 %d 节点的数据,weight = Height = ,输入完毕按回车结束!\r\n",i+1);
scanf("%d %d", &weight,&height);
InsetData.weight = weight;
InsetData.hight = height;
printf("weight = %d height = %d\r\n",weight,height);

if(LinkNode_Create(&AppleInfo_head, &InsetData) > NULL)
{
printf("节点 %d 创建成功!\r\n\r\n\r\n",i+1);
}
else
{
printf("节点 %d 创建失败!\r\n\r\n\r\n",i+1);
}
}
printf("\r\n");
break;

case 2:
/******* 删除链表中的某个节点 ***************************************************/
printf("请输入需要删除的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
destroy_LinkNode(&AppleInfo_head, Num);
printf("\r\n");
break;

case 3:
printf("链表数据为:\r\n");
print_LinkNode_Info(&AppleInfo_head);
printf("\r\n");
break;

case 4:
printf("请输入需要查找的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
search_LinkNode_Info(&AppleInfo_head, Num);
printf("\r\n");
break;

case 5:
printf("请输入需要查找的链表节点的weight,按回车结束!\r\n");
scanf("%d", &Num);
search_Same_LinkNode_Info(&AppleInfo_head, Num);
printf("\r\n");
break;

case 8:
system("cls");
break;

case 9:
printf("退出链表控制台,请再次运行程序!\r\n");
return;
break;

default:
printf("无效的键值,请重新输入!\r\n");
break;
}
}
return 0;
}




常用数据结构:单向链表和双向链表的实现_链表_07

标签:weight,单向,链表,pf,printf,数据结构,LinkNode,节点
From: https://blog.51cto.com/wangjunlv/5953107

相关文章

  • 数据结构与算法概念
    目录引入概念第一次尝试算法的提出算法的概念算法的五大特性第二次尝试算法效率衡量执行时间反应算法效率单靠时间值绝对可信吗?时间复杂度与“大O记法”如何理解“大O记法......
  • 双链表实现双端队列
    双链表实现双端队列双端队列是一个从两端都可以进行进队出队的队列。代码:/***使用双链表实现双端队列*双端队列也就是在队列的两端都可以进行出队列以及入队列......
  • 链表的反转
    链表的反转单链表的反转关于单链表的反转最重要的是要弄清楚边界问题。我们首先记录以下头节点的下一个节点然后让头节点的下一“指针”next指向前指针pre刚开始为null,......
  • 单链表与队列和栈
    单链表与队列和栈使用单链表实现队列队列是一个先进先出的数据结构,它包括进队、出队、获取队列大小等功能。代码:/***使用单链表实现队列*队列是一个先进先出的......
  • [leetcode]第 2 天 链表(简单)
    06.从尾到头打印链表思路说到从尾到头,很容易想到可以用到栈的方式进行处理,那么问题就转化成了如何用辅助栈完成打印链表。可以从链表的头节点开始,依次将每个节点压入栈......
  • 数据结构(6):串(下)
    上一回,我们看到串的定义和基本操作,这一会,我们看到串的一个典型应用——模式匹配!简单的模式匹配算法子串的定位操作通常称为串的模式匹配,它求的是子串(常称模式串)在主串中的位......
  • 你总是要学会数据结构的
    年末了,身边很多人都在考虑辞职这件事~ 午休的时候,和HR聊起了这个话题,她说,最近公司是“新人来,老人走呀”,年底了,她招聘的压力是越来越大了! 普遍来说,即便是再不能忍受这份......
  • 剑指Offer——链表的环以及环的入口
    在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。例如,链表1->2->3->3->4->4->5处理后为1->2->5解题思路这个题包含两个子问......
  • 数据结构冲刺题
    简答题Q01:数据结构的定义?数据结构三要素是什么?数据结构是相互之间存在一种或多种特定关系的数据元素的集合。数据结构三要素:逻辑结构、存储结构、数据运算Q02:逻辑结......
  • 数据结构与算法学习笔记
    本文是王争老师的《算法与数据结构之美》的学习笔记,详细内容请看王争的专栏 。有不懂的地方指出来,我做修改。数据结构与算法思维导图数据结构指的是“一组数据的存储结构”......