提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
每个元素本身由两部分组成:
1、本身的信息,称为"数据域"
2、指向直接后继的指针,称为"指针域"
SeqList.h头文件代码如下
typedef int SLDatetype;
typedef struct SListNode
{
SLDatetype val;//数据域
struct SListNode* next;//指针域
}SListNode;
//打印链表
void SLTPrint(SListNode*phead);
//销毁链表
void SLTDestroy(SLNode** pphead);
//尾插
void SLTPushBack(SListNode** pphead,SLDatetype x);
//头插
void SLTPushFront(SListNode** pphead,SLDatetype x);
//尾删
void SLTPopBack(SListNode** pphead);
//头删
void SLTPopFront(SListNode** pphead);
//查找
SListNode*SLTFind(SListNode* plist,SLDatetype x);
//在pos前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLDatetype x);
//在pos前面删除
void SLTErase(SListNode** pphead,SListNode* pos);
//在pos后面位置插入
void* SLTInsertAfter(SListNode* pos,SLDatetype x);
//在pos后面删除
void* SLTEraseAfter(,SListNode* pos)
链表打印不需要断言的,链表和顺序表不同,当链表中没有元素时,链表为空链表,头指针指向的就是NULL了,所以断言就会出问题。
void SLTPrint(SListNode*phead)
{
SListNode* tail=phead;
//遍历链表
while(tail->next!=NULL)
{
printf("%d->",tail->val);
//同时更新tail
tail=tail->next;
}
printf("NULL");
}
注意:销毁操作不允许直接free(phead),因为链表在物理结构上不是连续存放的,必须要一个结点一个结点去释放
void SLTDestroy(SLNode** pphead)
{
//断言,防止传空指针
assert(pphead);
SLNode* cur = *pphead;
//空链表不进循环
while (cur)
{
SLNode* next = cur->next;
//释放每一个结点
free(cur);
cur = next;
}
//最后记得一定要置空
*pphead = NULL;
}
因为我们后面插入部分都需要创建结点,所以我们专门设计一个创建结点的功能函数,既方便又减少了重复代码。
SListNode* CreaetNode(SLDatetype x)
{
SListNode* newnode=(SListNode*)malloc(sizeof(SListNode));
//判断malloc是否开辟成功结点
if(newnode==NULL)
{
//开辟失败直接退出程序
printf("malloc fail");
exit(-1);
}
newnode->val=x;
newnode->next=NULL;
return newnode;
}
思想
void SLTPushBack(SListNode**pphead,SLDatetype x)
{
//断言,防止传空指针
assert(pphead);
//创建结点
SListNode*newnode=CreatNode(x);
if(*pphead==NULL)
{
*pphead=newnode;
}
else
{
SListNode*tail=*pphead;
//找尾,指针为空不进循环
while(tail->next!=NULL)
{
//更新tail
tail=tail->next;
}
//指向新的结点
tail->next=newnode;
}
}
测试及测试结果
尾插
void Test1()
{
SListNode*plist=NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 2);
SLTPushBack(&plist, 3);
SLTPushBack(&plist, 4);
SLTPrint(plist);
}
思想
void SLTPushFront(SListNode** pphead, SLDatetype x)
{
//断言,防止传过来的是空指针
assert(pphead);
SListNode*newnode=CreatNode(x);
newnode->next=*pphead;
*pphead=newnode;
}
测试及测试结果
头插
void Test2()
{
SListNode* plist = NULL;
SLTPushFront(&plist, 1);
SLTPushFront(&plist, 2);
SLTPushFront(&plist, 3);
SLTPushFront(&plist, 4);
SLTPrint(plist);
}
思想
void SLTPopBack(SListNode** pphead)
{
//断言,防止传过来空指针
assert(pphead);
//暴力检查法
assert(*pphead);
//一个结点
if((*pphead)->==NULL)
{
free(*pphead);
*pphead=NULL;
}
//多个结点
else
{
//双指针,找尾
SListNode*prve=NULL;
SListNode*tail=*pphead;
while(tail->next==NULL)
{
//tail始终在prev的前面
prev=tail;
//更新tail
tail=tail->next;
}
//释放空间
free(tail);
//置空
prve->next=NULL;
}
}
测试及测试结果
我们直接在Test1的基础上测试尾删
void Test1()
{
SListNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 2);
SLTPushBack(&plist, 3);
SLTPushBack(&plist, 4);
SLTPrint(plist);//打印1、2、3、4
SLTPopBack(&plist);//尾删一个
SLTPrint(plist);//打印1、2 、3
SLTPopBack(&plist);//尾删一个
SLTPrint(plist);//1、 2
SLTPopBack(&plist);//再删后面一个
SLTPrint(plist);//1
SLTPopBack(&plist);//删空了
SLTPrint(plist);//打印NULL
}
思想
void SLTPopFront(SListNode** pphead)
{
assert(pphead);
//多个结点
SListNode*tmp=*pphead;
*pphead=(*pphead)->next;
//释放指向的空间
free(tmp);
}
测试
void TestSLT2()
{
SListNode* plist = NULL;
SLTPushFront(&plist, 1);
SLTPushFront(&plist, 2);
SLTPushFront(&plist, 3);
SLTPushFront(&plist, 4);
SLTPrint(plist);//头插打印4->3->2->1->NULL
SLTPopFront(&plist);//头删一个
SLTPrint(plist);//3->2->1->NULL
}
从链表头结点开始遍历,依次对比链表中数据域的值是否等于x,等于返回该节点指针,若链表中找不到、不存在就返回空并退出程序。
SListNode* SLTFind(SListNode* phead, SLDateType x)
{
//断言,防止传空指针
assert(phead);
SListNode* cur=phead;
//遍历
while (cur)
{
if (cur->val == x)
{
return cur;
}
else
{
cur=cur->next;
}
}
return NULL;
}
思想
void SLTInsert(SListNode**pphead,SListNode*pos,SLDatetype x)
{
assert(pphead);
assert(*pphead);
assert(pos);
if(*pphead==pos)
{
//头插
SLTPushFront(pphead,x);
}
else
{
SListNode*prev=*pphead;
while(prev->next!=pos)
{
prev=prev->next;
}
SListNode*newnode=CreatNode(x);
prve->next=newnode;
newnode->next=pos;
}
}
测试及测试结果
void TestSLT3()
{
SListNode* plist = NULL;
SLTPushFront(&plist, 1);
SLTPushFront(&plist, 2);
SLTPushFront(&plist, 3);
SLTPushFront(&plist, 4);
SLTPrint(plist);
SListNode* pos = SLTFind(plist, 4);
SLTInsert(&plist, pos, 40);
SLTPrint(plist);
pos = SLTFind(plist, 2);
SLTInsert(&plist, pos, 20);
}
思想
void SLTErase(SListNode** pphead, SListNode* pos)
{
assert(pphead);
assert(*pphead);
assert(pos);
if(*pphead==pos)
{
//头删
SLTPopFront(pphead);
}
else
{
SListNode*prve=*pphead;
while(prev->next=pos)
{
prev=prev->next;
}
prev->next=pos->next;
free(pos);
pos=NULL;
}
}
测试及测试结果
void TestSLT4()
{
SLNode* plist = NULL;
//插入数据
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 2);
SLTPushBack(&plist, 3);
SLTPushBack(&plist, 4);
SLTPrint(plist);
SLNode* pos = SLTFind(plist, 1);
SLTErase(&plist, pos);
SLTPrint(plist);
pos = SLTFind(plist, 3);
SLTErase(&plist, pos);
SLTPrint(plist);
}
void SLTInsertAfter(SListNode* pos, SLDateytype x)
{
//断言,空指针NULL不能指向下一个结点
assert(pos);
SListNode* newnode = CreatNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SLTEraseAfter(SListNode* pos)
{
assert(pos);
//断言,如果pos是最后一个结点,就不用再删除了
assert(pos->next);
SListNode* tmp = pos->next;
pos->next = pos->next->next;
free(tmp);
tmp = NULL;
}
//打印
void SLTPrint(SListNode*phead)
{
SListNode* tail=phead;
//遍历链表
while(tail->next!=NULL)
{
printf("%d->",tail->val);
//同时更新tail
tail=tail->next;
}
printf("NULL");
}
//销毁
void SLTDestroy(SLNode** pphead)
{
//断言,防止传空指针
assert(pphead);
SLNode* cur = *pphead;
//空链表不进循环
while (cur)
{
SLNode* next = cur->next;
//释放每一个结点
free(cur);
cur = next;
}
//最后记得一定要置空
*pphead = NULL;
}
//创建结点
SListNode* CreaetNode(SLDatetype x)
{
SListNode* newnode=(SListNode*)malloc(sizeof(SListNode));
//判断malloc是否开辟成功结点
if(newnode==NULL)
{
//开辟失败直接退出程序
printf("malloc fail");
exit(-1);
}
newnode->val=x;
newnode->next=NULL;
return newnode;
}
//尾插
void SLTPushBack(SListNode**pphead,SLDatetype x)
{
//断言,防止传空指针
assert(pphead);
//创建结点
SListNode*newnode=CreatNode(x);
if(*pphead==NULL)
{
*pphead=newnode;
}
else
{
SListNode*tail=*pphead;
//找尾,指针为空不进循环
while(tail->next!=NULL)
{
//更新tail
tail=tail->next;
}
//指向新的结点
tail->next=newnode;
}
}
//头插
void SLTPushFront(SListNode** pphead, SLDatetype x)
{
//断言,防止传过来的是空指针
assert(pphead);
SListNode*newnode=CreatNode(x);
newnode->next=*pphead;
*pphead=newnode;
}
//尾删
void SLTPopBack(SListNode** pphead)
{
//断言,防止传过来空指针
assert(pphead);
//暴力检查法
assert(*pphead);
//一个结点
if((*pphead)->==NULL)
{
free(*pphead);
*pphead=NULL;
}
//多个结点
else
{
//双指针,找尾
SListNode*prve=NULL;
SListNode*tail=*pphead;
while(tail->next==NULL)
{
//tail始终在prev的前面
prev=tail;
//更新tail
tail=tail->next;
}
//释放空间
free(tail);
//置空
prve->next=NULL;
}
}
//头删
void SLTPopFront(SListNode** pphead)
{
assert(pphead);
//多个结点
SListNode*tmp=*pphead;
*pphead=(*pphead)->next;
//释放指向的空间
free(tmp);
}
//查找
SListNode* SLTFind(SListNode* phead, SLDateType x)
{
//断言,防止传空指针
assert(phead);
SListNode* cur=phead;
//遍历
while (cur)
{
if (cur->val == x)
{
return cur;
}
else
{
cur=cur->next;
}
}
return NULL;
}
//在pos前面插入
void SLTInsert(SListNode**pphead,SListNode*pos,SLDatetype x)
{
assert(pphead);
assert(*pphead);
assert(pos);
if(*pphead==pos)
{
//头插
SLTPushFront(pphead,x);
}
else
{
SListNode*prev=*pphead;
while(prev->next!=pos)
{
prev=prev->next;
}
SListNode*newnode=CreatNode(x);
prve->next=newnode;
newnode->next=pos;
}
}
//删除pos位置
void SLTErase(SListNode** pphead, SListNode* pos)
{
assert(pphead);
assert(*pphead);
assert(pos);
if(*pphead==pos)
{
//头删
SLTPopFront(pphead);
}
else
{
SListNode*prve=*pphead;
while(prev->next=pos)
{
prev=prev->next;
}
prev->next=pos->next;
free(pos);
pos=NULL;
}
}
//在链表pos后面插入
void SLTInsertAfter(SListNode* pos, SLDateytype x)
{
//断言,空指针NULL不能指向下一个结点
assert(pos);
SListNode* newnode = CreatNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
//在链表pos后面删除
void SLTEraseAfter(SListNode* pos)
{
assert(pos);
//断言,如果pos是最后一个结点,就不用再删除了
assert(pos->next);
SListNode* tmp = pos->next;
pos->next = pos->next->next;
free(tmp);
tmp = NULL;
}