与顺序表相同,链表也是一种线性表。与顺序表不同的是,链表的物理存储结构是用一组地址任意的存储单元存储数据。它不像顺序表那样需要占据一段地址连续存储空间,而是将存储单元分散在内存的任意地址上。
在链表结构中,每个数据元素都存放在链表中的一个结点(node)上,而每个结点之间通过指针将其连接起来,这样就形成了一条如“链”的结构。
在C程序中,链表中的每个结点都可以用结构体来表示。在链表的每个结点中都必须有一个存放指针(地址)的域,也叫做指针域,指针域用来保存后继结点的地址,这样就将每个结点连接在一起,形成一条链。
一个链表中通常有一个表头,表头的用来保存第一个结点的地址。一个链表的最后一个结点的指针域要置空(NULL),因为它没有后继结点。
单链表的特点:
除“第一个”数据元素外,其余数据元素有且仅有一个 前驱元素 prev,
除“最后一个”数据元素外,其余数据元素有且仅有一个 后继元素 next
单链表的每个结点只有一个指针域
结点:每一个结点都包含两个部分:数据域和指针域。数据域用于存放数据元素,指针域用于存放后继结点的地址。
头指针:无论链表是否为空,头指针均不为空,头指针是链表的必要元素,头指针指向表头结点
头结点:放在第一个元素结点之前,其数据域一般无意义(当然也可以用来存放链表的长度等)
首元结点:第一个元素的结点,它是表头结点之后的第一个结点。
带头结点的单链表在后期的维护中更方便,头结点与其他结点一样拥有
数据域和指针域,头结点的数据域可以不存储任何信息,但也可以存储如链表长度等附加信息。 头结点的指针域用于保存首元结点的地址。带头结点的单链表的相关代码如下。
单链表的结点(LNode)通常使用结构体表示。
typedef struct node
{
//结点数据域
int data;
//结点指针域
struct node *next;
}LNode;
单链表的头结点(HNode)也使用结构体表示,头结点的指针域保存首元结点的地址,所以其指针域的类型需要与元素结点类型相同。
typedef struct head
{
//记录链表长度
int len;
LNode *next;
}HNode;
创建一个带头结点的单链表,并返回一个指向单链表头结点的头指针。头指针用来标识单链表,保存单链表的入口地址。
/***************************************************************
函数功能: 创建带头结点的单链表
入口参数: 无
返回值: head(单链表头指针)
****************************************************************/
HNode *create_linked_list(void)
{
//创建一个头指针
HNode*head = NULL;
//创建一个头结点,并将头指针指向头结点
head = (HNode*)malloc(sizeof(HNode));
head->len = 0;
head->next = NULL;
return head;
}
打印单链表的所有元素。
/***************************************************************
函数功能: 打印带头结点的单链表
入口参数: head(单链表头指针))
返回值: 无
****************************************************************/
void print_linked_list(HNode*head)
{
LNode *list = NULL;
list = head->next;
while(list)
{
printf("%d ", list->data);
list = list->next;
}
printf("\n");
}
例如:
单链表:1 2 3 4 5 6 7 8 9
输出:1 2 3 4 5 6 7 8 9
在单链表最后一个结点之后插入一个新结点,并将新插入的结点的指针域置NULL,单链表最后一个结点没有后继节点。
/***************************************************************
函数功能: 在单链表最后一个结点之后插入一个结点
入口参数:
参数1:head(单链表头指针)
参数2:x(需要保存的元素数据)
返回值: head(单链表头指针)
****************************************************************/
HNode *add_linked_list_last(HNode *head,int x)
{
LNode *last_node = NULL;
last_node = head->next;
//判断是否为最后一个结点
while(last_node->next)
{
last_node=last_node->next;
}
//申请开辟一个结点空间
LNode *new_node = (LNode*)malloc(sizeof(LNode));
new_node->data = x;
new_node->next=NULL;
//将结点插入最后
last_node->next = new_node;
last_node = new_node;
head->len++;//链表长度加1
return head;
}
例如:
单链表:1 2 3 4 5 6 7 8 9
插入10后:1 2 3 4 5 6 7 8 9 10
在单链表首元结点之前插入一个新结点,并将头结点的指针指向新结点。
/***************************************************************
函数功能: 在单链表首元结点之前插入一个结点
入口参数:
参数1:head(单链表头指针)
参数2:x(需要保存的元素数据)
返回值: head(单链表头指针)
****************************************************************/
HNode *add_linked_list_first(HNode *head,int x)
{
LNode *new_node = NULL;
//申请开辟一个结点空间
new_node = (LNode*)malloc(sizeof(LNode));
new_node->data = x;//保存需要插入的元素
new_node->next = NULL;
//将新结点插入到第一个结点之前
new_node->next = head->next;
head->next = new_node;
head->len++;
return head;
}
例如:
单链表:2 4 7 8 9 1
插入11后:11 2 4 7 8 9 1
删除单链表中的第N个结点,需要将第N-1个结点的后继指针指向第N+1个结点,然后将第N个结点的后继指针置NULL,然后再释放第N个结点的空间。
/***************************************************************
函数功能: 删除单链表中的第N个结点
入口参数:
参数1:head(单链表头指针)
参数2:n(第N个结点)
返回值: head(单链表头指针)
****************************************************************/
HNode *delete_theN_node(HNode *head,int n)
{
//判断n是否大于链表长度
if (n > head->len || n < 1)
{
printf("该结点不存在!\n");
return 0;
}
LNode *now_node = NULL;
LNode *prev_node = NULL;
now_node = head->next;
//删除第一个结点
if (1 == n)
{
head->next = now_node->next;
now_node->next = NULL;
free(now_node);
now_node = NULL;
head->len--;
}
//删除最后一个结点
else if(head->len == n)
{
while(--n)
{
prev_node = now_node;
now_node = now_node->next;
}
prev_node->next = NULL;
free(now_node);
now_node = NULL;
head->len--;
}
//删除中间某个结点
else
{
while(--n)
{
prev_node = now_node;
now_node = now_node->next;
}
prev_node->next = now_node->next;
now_node->next = NULL;
free(now_node);
now_node = NULL;
head->len--;
}
return head;
}
例如:
单链表:2 4 7 8 9 1
删除第2个结点后: 2 7 8 9 1
前提:单链表中不包含重复元素。
/***************************************************************
函数功能: 删除单链表中元素为X的结点(单链表中不包含重复元素)
入口参数:
参数1:head(单链表头指针)
参数2:x(删除的元素数据)
返回值: head(单链表头指针)
****************************************************************/
HNode *delete_num(HNode *head,int x)
{
LNode *now_node = NULL;
LNode *prev_node = NULL;
now_node = head->next;
//判断X是不是第一个结点的元素
if(x == now_node->data){
head->next = now_node->next;
now_node->next = NULL;
free(now_node);
now_node = NULL;
head->len--;
return head;
}
//判断中间
while(now_node->next)
{
if(x == now_node->data){
prev_node->next = now_node->next;
now_node->next = NULL;
free(now_node);
now_node = NULL;
head->len--;
return head;
}
else{
prev_node = now_node;
now_node = now_node->next;
}
}
//判断最后一个结点的元素是否为X
if(x == now_node->data){
prev_node->next = NULL;
free(now_node);
now_node = NULL;
head->len--;
}
else{
printf("链表中无%d这个元素\n",x);
return 0;
}
return head;
}
例如:
单链表:2 4 7 8 9 1
删除元素9后:2 4 7 8 1
/***************************************************************
函数功能: 删除单链表中的重复元素
入口参数: head(单链表头指针)
返回值: head(单链表头指针)
****************************************************************/
HNode *delete_repetitive_num(HNode*head)
{
LNode *now_node = NULL;
LNode *prev_node = NULL;
now_node = head->next;
while(now_node->next){
prev_node = now_node;
now_node = now_node->next;
//判断相邻两个元素是否相等
if(prev_node->data == now_node->data){
prev_node->next = now_node->next;
now_node->next = NULL;
free(now_node);
now_node = prev_node;
}
}
return head;
}
例如:
单链表:1 1 2 2 3 3 3 5 5
删除后:1 2 3 5
销毁除头结点之外的结点。
/***************************************************************
函数功能: 销毁除头结点之外的结点
入口参数: head(单链表头指针))
返回值: head(单链表头指针)
****************************************************************/
HNode *destroy_linked_list(HNode *head)
{
LNode *now_node = NULL;
//从第一个元素结点开始销毁
while(head->next){
now_node = head->next;
if(now_node->next == NULL){
head->next = NULL;
free(now_node);
now_node = NULL;
head->len--;
break;
}
head->next = now_node->next;
now_node->next = NULL;
free(now_node);
now_node = NULL;
head->len--;
}
return head;
}
说明:此逆置不改变结点原来的位置,只交换两个结点存储的数据。
/***************************************************************
函数功能: 逆置单链表(交换元素数据)
入口参数: head(单链表头指针)
返回值: head(单链表头指针)
****************************************************************/
HNode *reverse_linked_list(HNode *head)
{
int n = head->len;
int temp;
int i,j;
printf("链表长度:%d\n",n);
LNode *first_node = NULL;
LNode *temp1_node = NULL;
LNode *temp2_node = NULL;
first_node = head->next;
temp1_node = first_node;
//如果链表元素个数为奇数则(n-1)%2,反之n%2
if(n%2 == 0||(n-1)%2==0)
{
//不管是奇数个元素还是偶数个元素,都只需要交换n/2次
//奇数个元素其最中间那一个元素不需要交换
for(i=0;i<n/2;i++)
{
temp2_node = first_node;
for(j=0;j<n-i-1;j++)
{
temp2_node = temp2_node->next;
}
temp = temp1_node->data;
temp1_node->data = temp2_node->data;
temp2_node->data = temp;
//指向第一个结点的指针往后移动一个
temp1_node = temp1_node->next;
}
}
return head;
}
例如:
单链表:3 2 4 5 10 8 1
逆置后:1 8 10 5 4 2 3
/***************************************************************
函数功能: 将两个链表归并为一个有序链表
入口参数:
参数1:head1(单链表头指针)
参数2:head2(单链表头指针)
返回值: head3(单链表头指针)
****************************************************************/
HNode *combine_linked_list(HNode*head1,HNode*head2)
{
HNode *head3 = NULL;
LNode *now_node = NULL;
LNode *next_node = NULL;
int flag = 0;
int temp;
int n;
now_node = head1->next;
//找head1的最后一个结点
while(now_node->next){
now_node = now_node->next;
}
//连接head1和head2
now_node->next = head2->next;
//合并
head3 = head1;
head3->len = (head1->len) + (head2->len);
n = head3->len;
//冒泡排序
for(int i=0;i<n-1;i++)
{
now_node = head3->next;
next_node = now_node;
for(int j=0;j<n-1-i;j++)
{
next_node = next_node->next;
if(now_node->data > next_node->data)
{
temp = now_node->data;
now_node->data = next_node->data;
next_node->data = temp;
flag = 1;
}
now_node = now_node->next;
}
if(flag == 0){
break;
}
}
return head3;
}
例如:
单链表1:5 4 3 2 1
单链表2:9 6 8 7
归并后:1 2 3 4 5 6 7 8 9
/***************************************************************
函数功能: 修改第N个结点的数据
入口参数:
参数1:head(单链表头指针)
参数2:n(第N个结点)
参数3:更新的数据
返回值: head3(单链表头指针)
****************************************************************/
HNode *change_theN_node(HNode *head,int n,int x)
{
//判断n是否大于链表长度
if (n > head->len || n < 1)
{
printf("该结点不存在!\n");
return 0;
}
LNode *now_node = NULL;
now_node = head->next;
while(--n)
{
now_node = now_node->next;
}
now_node->data = x;
return head;
}
例如:
单链表:5 4 3 2 1
更新第2个结点数据为12:5 12 3 2 1
/***************************************************************
函数功能: 查找值为X的元素
入口参数:
参数1:head(单链表头指针)
参数2:x(查找的值)
返回值: 0 表示不存在,1表示存在
****************************************************************/
int find_data_linked_list(HNode *head,int x)
{
LNode *now_node = NULL;
now_node = head->next;
while(now_node){
if(now_node->data == x){
return 1;
}
now_node = now_node->next;
}
return 0;
}
int main(int argc, char const *argv[])
{
int num;
int n;
//创建一个头指针用于标识链表
HNode *phead = NULL;
//创建一个带头结点的单链表
phead = create_linked_list();
LNode*new_node = NULL;
LNode*last_node = NULL;
printf("请向单链表输入数据:");
do{
scanf("%d",&num);
new_node = (LNode*)malloc(sizeof(LNode));
new_node->data = num;
new_node->next = NULL;
if (phead->next == NULL)
{
phead->next = new_node;
last_node = new_node;
phead->len++;
}
else
{
last_node->next = new_node;
last_node = new_node;
phead->len++;
}
}while(getchar() != '\n');
//打印链表所有元素
printf("链表长度:%d\n",phead->len);
printf("链表所有元素:");
print_linked_list(phead);
//尾插法
//头插法
//删除第N个结点
//查找数据
return 0;
}
注意:该文章仅供学习交流不得转载商用。
前文,我们实现了认识了链表这一结构,并实现了无头单向非循环链表,接下来我们实现另一种常用的链表结构,带头双向循环链表。如有仍不了解单向链表的,请看这一篇文章(7条消息)【数据结构和算法】认识线性表中的链表,并实现单向链表_小王学代码的博客-CSDN博客目录前言一、带头双向循环链表是什么?二、实现带头双向循环链表1.结构体和要实现函数2.初始化和打印链表3.头插和尾插4.头删和尾删5.查找和返回结点个数6.在pos位置之前插入结点7.删除指定pos结点8.摧毁链表三、完整代码1.DSLinkList.h2.DSLinkList.c3.test.c总结前言带头双向循环链表,是链表中最为复杂的一种结
1.单链表单链表是多个节点通过指针串联起来的线性结构,每个节点分为两部分,一个是数据域,一个为指针域,头节点的数据域为空,最后一个节点的指针域胃为空,链表的前一个节点的指针域,存放的是下一个节点的地址。数据域:存放数据;指针域:指向下一个节点的指针。头节点的作用:为了方便操作整个链表,它并不保存具有实际意义的数据。创建链表的步骤(1)构建节点计算机中没有现成的节点,我们需要自己创建它。任意的节点都包含了两部分:左边部分data存储数据,右边部分next存储指针,就是下一个节点的地址。data中可以存放任意数据,包括int,float,double等,可以存放单个数据,也尅存放多个数据。例子构建
我正在尝试解决Go中的leetcode问题来自学这门语言。我有一个单链表和一个插入函数:typeListNodestruct{ValintNext*ListNode}funcInsert(listNode*ListNode,iint){//@fixmehowtocheckthefirstnode?iflistNode==nil{listNode.Val=ilistNode.Next=nil}else{for;;listNode=listNode.Next{iflistNode.Next==nil{listNode.Next=&ListNode{i,nil}break}}}}funcma
我使用自定义端点行为扩展来拦截消息,因为它们是由我的WCF服务端点接收的,使用IDispatchMessageInspector。我像这样检索消息内容:publicobjectAfterReceiveRequest(refMessagerequest,IClientChannelchannel,InstanceContextinstanceContext){MessageBuffermessageBuffer=request.CreateBufferedCopy(Int32.MaxValue);Messagemessage=messageBuffer.CreateMessage();u
前言: 对于链表,上一篇的单链表解决了顺序表的一部分缺陷,但并没有彻底的解决顺序表的问题,比如在进行单链表尾插尾删的时候还是需要进行遍历找尾,并没有达到全部的O(1),并且在头插的时候还要分情况来考虑,比如传入为空指针和不是空指针时候还要分情况考虑,对于指针的改变还要传二级指针,这对于一部分人来说并不熟悉,所以!!!今天看完这篇文章,掌握带双向循环数据表,让我们不再害怕链表的增删插改😎😎 💞💞 欢迎来到小马学习代码博客!!!! 思维导图:目录一、链表实现前的准备 💜1.1结构图:💜1.2初步的理解:二、带头双向链表功能实现前的准备🤎 2.1链表实现所需要的头文件:
🖊作者:Djx_hmbb📘专栏:数据结构😆今日分享:“Oncinablumoon”:“罕见的,千载难逢的”(出现在19世纪,指的是"在一个月内出现的第二次圆月”,这种现象每隔32个月发生一次。)文章目录✔单链表的功能实现:🔎申请一个结点空间:🔎构建n个链表:🔎打印链表:🔎尾插:🔎尾删:🔎头插:🔎头删:🔎查找:🔎在pos位置后插入x:🔎在pos位置前插入x:🔎删除pos位置后一个指针:🔎删除pos位置的指针:🔎释放空间:✔头文件(详情):✔测试文件(详情):家人们,点个:typedefstruct_PROGRAM_ITEM{SLIST_ENTRYItemEntry;ULONGSignature;/*MYDATA*/}PROGRAM_ITEM,*PPROGRAM_ITEM;intmain(){ULONGCount;PSLIST_ENTRYpFirstEntry,pListEntry;PSLIST_HEADERpListHead;PPROGRAM_ITEMpProgramItem;pListHead=(PSLIST_HEADER)_aligned_malloc(sizeof(SLIST_HEADER),MEMORY_A
我创建了一个WCF服务并公开了三个端点,它们是basicHttpBinding、wsHttpBinding和webHttpBinding。这是我使用WCF进行实验的测试服务。但是,每当我使用.svc文件添加服务引用时,我只会得到两个(基本和ws)端点。由于某种原因,似乎没有公开第三个(webHttpBidning)端点。要重现此问题,请创建一个WCF应用程序项目,删除Service1服务,添加名为TestService的新项目>WCF服务,并将配置文件更改为以下内容:这里是ITestService.cs的代码:[ServiceContract]publicinterfaceITestS
我已经为我的WCF服务创建了2个端点。它在basicHttpBinding上工作正常,但在webHttpBinding上会导致错误。错误=未找到端点。操作合约定义[OperationContract][WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.WrappedRequest,ResponseFormat=WebMessageFormat.Json)]VINDescriptionCallADSWebMethod(stringvin,stringstyleID);web.config:请建议我如何解决这个问题?
作者:半身风雪上一节:创建K8s集群项目简介:上一节我们一起学习了,如何去部署一个K8S的应用程序,这一节,我们主要讲解一下,K8S应用的框架结构。K8S应用pod结点目标一、KubernetesPods1.1、Kubernetes中的pod是做什么的二、工作结点三、故障排除3.1、常见kubectl命令3.2、可视化界面四、pod资源详情总结目标本节我将和大家一起学习Kubernetes应用中的pod结点了解KubernetesPod。了解Kubernetes工作节点。对已部署的应用故障排除。一、KubernetesPods在上一节中,我们一起学会了如何使用kubectl创建一个应用。这里我