目录
前言
单链表:
单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它不要求在逻辑上相邻的两个元素在物理位置上也相邻。
一、单链表的特点?
1.单链表不要求逻辑上相邻的两个元素在物理位置上也相邻,因此不需要连续的存储空间。
2.单链表是非随机的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。
3.对于每个链表结点,除了存放元素自身的信息外,还需要存放一个指向其后继的指针。
二、带头节点的好处
为了方便满足插入和删除基本操作,我们在链表的头部加入一个“头结点”,如果没有头结点,第一个结点的插入和删除操作跟其他结点不同,需要单独分析,为了省去这个麻烦,因此我们定义了一个头结点,头结点的类型与数据结点一致,标识链表的头指针变量L中存放该结点的地址,这样即使是空表,头指针变量L也不为空了。
头结点的加入使得“第一个结点”的问题不存在了,也使得处理“空表”和“非空表”的操作变的一致。
头结点的加入纯粹是为了使运算方便,它的数据域即data是没有定义的,指针域中存放的是第一个数 据结点的地址,空表时,指针域为NULL。
三、带头节点的链表的实现及代码
(一)带头结点的链表代码
1.单链表的定义
struct Lnode
{
int date;
struct Lnode* next; 单向链表由数据域和指针域构成结构体
};
typedef struct Lnode Lnode; 重定义
2.主函数
int main()
{
Lnode* Newshlistnode(Lnode * *t); ///新节点建立函数
void SHlistinit(Lnode * *t); ///头节点初始化函数
void printlistnode(Lnode * t); ///打印函数
Lnode* Cresatlistnode(Lnode * t); ///创建函数
Lnode* delelistnode(Lnode * t); ///删除节点函数
Lnode* insertlistnode(Lnode * t); //添加节点函数
void founderlistnode(Lnode * t); ///查找函数
void destory(Lnode * *t); ///销毁函数
void shilistsize(Lnode * t); ///求表长函数
Lnode* head;
SHlistinit(&head);
Cresatlistnode(head);
/*insertlistnode(head);
printlistnode(head);
delelistnode(head);
printlistnode(head);
founderlistnode(head);*/
shilistsize(head);
/*destory(&head);
printlistnode(head);*/
return 0;
}
3.头节点初始化
void SHlistinit(Lnode** t) ///初始化头节点
{
assert(t); ///检查指针不为空 assert函数实质上是一个宏,验证是否为空
*t = (Lnode*)malloc(sizeof(Lnode));, ///此处用二级指针,是为了避免值传递出现错误,
if ((*t) == NULL)
{
printf("创建出现错误\n"); ///开辟内存后检查是否开辟成功
exit(0);
}
(*t)->next = NULL; //头节点数据域不定义或者不要求
}
4.新节点的建立函数
Lnode* Newshlistnode(Lnode** t) /创建新节点
{
assert(t);
*t = (Lnode*)malloc(sizeof(Lnode));
if ((*t) == NULL)
{
printf("创建失败\n");
exit(0);
}
(*t)->next= NULL;
return (*t); 因为用的二级指针传址,所以此处可以不返回地址,
} 同理,返回地址的话其实可以不用二级指针