目录
1、关于单链表
顺序表的插入删除操作需要移动大量的元素,影响了运行效率,因此引入了线性表的链式存储——单链表。单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它不要求在逻辑上相邻的两个元素在物理位置上也相邻。
2.单链表的优缺点
优点:1.按需申请空间,不用则释放,较为灵活。
2.相较于顺序表,对于头/中部的数据插入删除操作无需移动数据。
缺点:1.每有一个数据都需要一指针链接之后的结点。
2.不支持随机访问。
3.单链表的初始化
typedef int SListData;//重定义数据类型,便于不同类型数据的存储
typedef struct SListNode
{
SListData data;//数据域
SListNode* next;//指针域,存储下一结点的地址
}SListNode;
4.申请新结点
由于对单链表插入数据时,总需要向内存动态申请一块空间存储数据及下一结点的地址,所以将的的此操作封装成函数,便于代码的简洁易读。
SListNode* BuySListNode()//申请一块空间并返回结点的指针
{
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));//动态申请内存
if (newnode == NULL)
{
printf(" SListPushBack::%s", strerror(errno));
exit(-1);//申请空间失败,错误退出
}
newnode->data = 0;
newnode->next = NULL;
return newnode;
}
函数动作内容:动态申请内存后返回结点的指针,并将该结点的数据域初始化为零,指针域
初始化为NULL。
5.关于单链表的插入(尾插)
void SListPushBack(SListNode** pphead, int data)//单链表尾插
{
SListNode* tail = *pphead;//将*p拷贝一份,便于可读性
assert(pphead);//断言p不能为空,否则错误退出
SListNode* newnode=BuySListNode();
newnode->data = data;//完成新结点数据域的更新
if (tail == NULL)//此时链表为空
{
*pphead = newnode;
}
else//单链表不为空
{
while (tail->next != NULL)//循环找到tail的指针域为空的结点
{
tail = tail->next;
}
tail->next = newnode;//将找到的tail指针域链接新申请的newnode
}
}
assert:断言函数,若参数为假则中断程序并报错。pphead作为二级指针,在传递参数正确时不可能为NULL,一旦发生错误,则为传参错误,便于检验 。
尾插可分两种情况讨论,第一:单链表为空,此时直接申请一块空间作为单链表的头部,此时链表的头指针需要发生变化为新申请的结点地址,为了保存新地址,因此我们需要二级指针作为参数来记忆新地址。 第二:单链表不为空,则直接找到单链表的尾部,即指针域为NULL的结点,将新申请的newnode结点链接到单链表末尾。
6.单链表的头插
此操作较为简单,对于空表和有数据的单链表来说,头插只需要先将新申请的结点newnode指针域赋值于原始头指针,再将原来的头指针更新为新申请的空间即可(注意更新顺序,否则要在申请变量存储原始的头指针,防止数据的更新导致找不到原来的头结点)。
void SListPushFront(SListNode** pphead, int data)//单链表头插
{
assert(pphead);
SListNode* newnode = BuySListNode();//申请新结点后直接完成数据更新和链接即可
newnode->data = data;
newnode->next = *pphead;
*pphead = newnode;
}
7.单链表的尾删
单链表的尾删要考虑三种情况。
第一:单链表为空,此时没有数据可以删除
第二:单链表只有一个结点,此时删除节点后,头结点释放并置空,因此要传入二级指针作为参数(传值和传址的区别)来记忆数据的更新。
第三:普通的多个结点的情况,此时只需要找到指针域为NULL的结点,但注意,我们需要的是删除最后一个结点,即倒数第二个结点的指针域需要置NULL来作为新的表尾。因此,我们需要利用定义一个指针来记住倒数第二个结点的pos。
void SListPopBack(SListNode** pphead)//单链表尾删
{
assert(pphead);
SListNode* tail = *pphead;
if (tail == NULL)//表空的情况
{
printf("表空,无法删除\n");
return;
}
// assert(*pphead);//此时采取暴力的方式,即当表空时直接报错退出程序无法删除
else
{
if (tail->next == NULL)//表中只有一个结点的情况
{
free(*pphead);
*pphead = NULL;
return;
}
else
{
SListNode* cur = 0;
while (tail->next)
{
cur = t