目的
学习单链表的基本结构及基本功能
代码内容
#include<stdio.h>
#include<malloc.h>
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef struct LNode
{
ElemType data;//数据域
struct LNode* next;//指针域
}LNode, *LinkList;
Status LinkList_Create(LinkList& L)//用尾插法创建一个带头结点的单链表,以输入0结束
{
ElemType node;
L = (LinkList)malloc(sizeof(LNode));//先创建一个带头结点的空链表
L->next = NULL;
printf("输入单链表中各元素值:(以输入0结束)\n");
scanf_s("%d", &node);//输入链表中第一个结点的数据值
LinkList r = L;//引入一个尾指针,使其始终指向当前表的表尾
while (node != 0)//如果输入的数据值为0,则结束循环
{
LinkList p = (LinkList)malloc(sizeof(LNode));//为新结点p分配空间
if (!p)
return ERROR;
p->data = node;//将输入的数据值存入新结点的数据域
r->next = p;//修改链,使新结点p插入到链表的表尾
r = p;
scanf_s("%d", &node);//输入链表中下一个结点的数据值
}
r->next = NULL;//最后尾结点的后继指针置空
return OK;
}
Status LinkList_Insert(LinkList& L, int i, ElemType e)//在单链表L的第i个数据元素之前插入新的元素e,i的合法值是1<=i<=n+1
{
LinkList p = L, s;//p指针指示链表中的头结点
int j = 0;//j指示p指针所指的结点在表中的位序号
while (p && j < i - 1)//找到第i个元素的前驱结点,并用p指针指向它
{
p = p->next;
++j;
}
if (!p || j > i - 1)//i不合法(找不到前驱结点)
return ERROR;
s = (LinkList)malloc(sizeof(LNode));//产生新的结点
s->data = e;
s->next = p->next;//修改链指针,让新结点插入到第i-1个元素结点p的后面
p->next = s;
return OK;
}
Status LinkList_Delete(LinkList& L, int i, ElemType& e)//删除单链表L中的第i个数据元素,并通过e返回其值,i的合法值是1<=i<=n
{
LinkList p = L, q;//p指针指示链表中的头结点
int j = 0;//j指示p指针所指向的结点在表中的位序号
while (p->next && j < i - 1)//找到被删除结点的前驱结点
{
p = p->next;
++j;
}
if (!p->next || j > i - 1)//i不合法(找不到前驱结点)
return ERROR;
q = p->next;//q指向待删结点
p->next = q->next;//修改链指针让待删结点从链中脱离出来
e = q->data;//用e保存待删结点的数据元素值
free(q);//释放待删结点空间
return OK;
}
Status LinkList_LocateElem(LinkList L, int i, ElemType& e)//查找单链表中第i个数据元素,如果查找成功,则通过e返回其数据元素值,i的合法值是1<=i<=n
{
LinkList p = L->next;//p指向链表中的首结点
int j = 1;//j记录p结点在表中的位序号
while (p && j < i)//沿着后继指针一个一个“点数”
{
p = p->next;
j++;
}
if (!p || j > i)//i不合法
return ERROR;
e = p->data;//用e返回第i个元素的值
return OK;
}
void LinkList_Output(LinkList L)//输出单链表L中各数据元素值
{
LinkList p = L->next;//p指向链表的首结点
printf("链表中的内容为:\n");
while (p)
{
printf("%d ", p->data);//输出p指针所指结点的数据值
p = p->next;//p指针后移
}
printf("\n");
printf("\n");
}
int main()
{
LinkList L;
int i;
ElemType e;
LinkList_Create(L);//用尾插法创建一个带头结点的单链表,以输入0结束
LinkList_Output(L);//输出单链表中各元素值
printf("输入插入位置:\n");
scanf_s("%d", &i);//输入插入位置
printf("输入待插入的元素值:\n");
scanf_s("%d", &e);//输入待插入的元素值
if (LinkList_Insert(L, i, e))
LinkList_Output(L);//输出插入操作后的单链表
else
printf("Insert failed!\n");
printf("输入删除位置:\n");
scanf_s("%d", &i);//输入删除位置
if (LinkList_Delete(L, i, e))
{
LinkList_Output(L);//输出删除操作后的单链表
printf("删除的元素是%d\n", e);
}
else
printf("Deletion failed!\n");
printf("输入待查找元素所在表中的位置:\n");
scanf_s("%d", &i);//输入待查找元素所在表中的位置
if (LinkList_LocateElem(L, i, e))
printf("%d Search succeeded!\n", e);//输出查找找到的元素值及“Search succeeded!”
else
printf("Search failed!\n");//输出“Search failed!”
return 0;
}
逻辑思路
编写基本框架
预定义
#include<stdio.h>
#include<malloc.h>
#define OK 1
#define ERROR 0
typedef ElemType;
typedef Status;
链表结点结构体定义
typedef struct LNode
{
ElemType data;//数据域,用于存放数据
struct LNode* next;//指针域,用于存储下一个结点的位置
}LNode, *LinkList;
代码解析
struct LNode* next;
-
struct LNode: 这里的struct LNode指的是一个结构体类型,名为LNode。这个结构体代表链表的一个节点,包含了两个部分:数据部分 (data) 和指向下一个节点的指针部分 (next)。 -
*next: 这个*表示next是一个指针,指向类型为struct LNode的节点。换句话说,next指向链表中下一个节点的内存地址。
tips:
可以将该结构体想象成一根铁链中的一个小圆环,小圆环由两部分组成:环内空隙、实体的铁环。
环内空隙用来存放东西,即数据域;实体铁环可以将两个环相扣,联系了两个空隙,使他们呈现线性关系,即指针(文字不好描述,可自行想象或用多个回形针串联参悟)
LNode, *LinkList;
-
LNode:- 这里的
LNode是一个类型别名,它代表了结构体LNode。通过typedef,你可以直接使用LNode而不必每次都写struct LNode。因此,LNode类型可以new一个实际的链表节点。
- 这里的
-
*LinkList:- 这里的
*LinkList是一个指针类型的别名。LinkList被定义为指向struct LNode的指针。通过LinkList,你可以方便地定义和使用链表指针,而不需要每次都写struct LNode*。
- 这里的
tips:
typedef struct LNode
{
}LNode, *LinkList;
可等同于
int A,B;
即typedef struct LNode(自定义类型LNode)等同于int
LNode, *LinkList等同于A,B
创建单链表(尾插法)
Status LinkList_Creat(LinkList& L)
{
ElemType node;
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
printf("输入单链表中各元素值:(以输入0结束)\n");
scanf_s("%d", &node);
LinkList r = L;
while (node != 0)
{
LinkList p = (LinkList)malloc(sizeof(LNode));
if (!p)
return ERROR;
p->data = node;
r->next = p;
r = p;
scanf_s("%d", &node);
}
r->next = NULL;
return OK;
}
代码解析
L = (LinkList)malloc(sizeof(LNode));
-
malloc(sizeof(LNode)):malloc是 C 语言中的一个函数,用于动态分配内存。sizeof(LNode)返回结构体LNode的大小(以字节为单位)。因此,malloc(sizeof(LNode))会分配足够的内存来存储一个LNode结构体的实例。
-
(LinkList):- 这是一个类型转换,将
malloc返回的void*指针转换为LinkList类型(即struct LNode*的指针类型)。 - 这是一种将通用指针转为特定指针类型的方式,以便可以使用更具体的数据结构。
- 这是一个类型转换,将
-
L =:- 这里
L是一个变量,其类型是LinkList,即指向struct LNode的指针。 - 这行代码的作用是将动态分配的内存地址(一个
LNode的指针)赋值给L。
- 这里
tips:
可与顺序表中的分配内存进行对比,可知双方在构成上基本没有区别
L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
(各部分含义见优快云)
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
即创建一个空表
LinkList r = L;
新建一个辅助指针r,用于跟踪链表的尾结点
while (node != 0)
{
LinkList p = (LinkList)malloc(sizeof(LNode));
if (!p)
return ERROR;
p->data = node;
r->next = p;
r = p;
scanf_s("%d", &node);
}
用while循环新建结点,并储值,r->next = p;连接结点,r = p;更新尾结点
r->next = NULL;
链表创建完成,将尾指针置空,表示无后续结点
编写输出模块
Status LinkList_Output(LinkList L)
{
LinkList p = L->next;
while (p)
{
printf("%d", p->data);
p = p->next;
}
printf("\n");
}
代码解析
LinkList p = L->next;
新建指针p,并使它指向头结点的下一个结点(头结点不储存元素)
创建主函数
int main()
{
}
编写基础功能
插入
Status LinkList_Insert(LinkList& L, int i, ElemType e)//在单链表L的第i个数据元素之前插入新的元素e,i的合法值是1<=i<=n+1
{
LinkList p = L, s;//p指针指示链表中的头结点
int j = 0;//j指示p指针所指的结点在表中的位序号
while (p && j < i - 1)//找到第i个元素的前驱结点,并用p指针指向它
{
p = p->next;
++j;
}
if (!p || j > i - 1)//i不合法(找不到前驱结点)
return ERROR;
s = (LinkList)malloc(sizeof(LNode));//产生新的结点
s->data = e;
s->next = p->next;//修改链指针,让新结点插入到第i-1个元素结点p的后面
p->next = s;
return OK;
}
代码逻辑
找到第i个元素的前驱结点,修改链指针插入
删除
Status LinkList_Delete(LinkList& L, int i, ElemType& e)//删除单链表L中的第i个数据元素,并通过e返回其值,i的合法值是1<=i<=n
{
LinkList p = L, q;//p指针指示链表中的头结点
int j = 0;//j指示p指针所指向的结点在表中的位序号
while (p->next && j < i - 1)//找到被删除结点的前驱结点
{
p = p->next;
++j;
}
if (!p->next || j > i - 1)//i不合法(找不到前驱结点)
return ERROR;
q = p->next;//q指向待删结点
p->next = q->next;//修改链指针让待删结点从链中脱离出来
e = q->data;//用e保存待删结点的数据元素值
free(q);//释放待删结点空间
return OK;
}
代码逻辑
找到前驱结点,使用辅助指针q记录待删结点,修改链接,释放待删结点
查找
Status LinkList_LocateElem(LinkList L, int i, ElemType& e)//查找单链表中第i个数据元素,如果查找成功,则通过e返回其数据元素值,i的合法值是1<=i<=n
{
LinkList p = L->next;//p指向链表中的首结点
int j = 1;//j记录p结点在表中的位序号
while (p && j < i)//沿着后继指针一个一个“点数”
{
p = p->next;
j++;
}
if (!p || j > i)//i不合法
return ERROR;
e = p->data;//用e返回第i个元素的值
return OK;
}
372

被折叠的 条评论
为什么被折叠?



