链表的概念
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
下面开始单链表
先创建一个结构体
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
动态申请结点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* node = (SListNode*)malloc(sizeof(SListNode));
//判断开辟节点是否成功
if (node == NULL)
{
printf("malloc fail\n");
exit(-1);
}
node->data = x;
node->next = NULL;
return node;
}
单链表的尾插
怎么尾插呢?
尾插的思想:
1.常规尾插:给个plist指针指向头结点,通过plist指针找到后面的结点。在定义一个tail指针找到尾结点,让尾节点指向新结点
2.链表为空,先指向新结点,在进行尾插
在将图的思路转换成代码
void SListPushBack(SListNode** pplist, SLTDateType x)
{
assert(pplist);//地址不能为空
//链表为空
if (*pplist==NULL)
{
SListNode* newnode = BuySListNode(x);
*pplist = newnode;
}
else
{
SListNode* tail = *pplist;
//找尾
while (tail->next !=NULL)
{
tail = tail->next;
}
SListNode* newnode = BuySListNode(x);
tail->next = newnode;
}
}
```c
//测试代码
void test()
{
SListNode *plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
这是单链表的尾插。
单链表的头插
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
assert(pplist);
SListNode* newnode = BuySListNode(x);
//pplist存plist的地址,解引用找到plist
newnode->next = *pplist;
*pplist = newnode;
}
SListPushFront(&plist, -1);
SListPrint(plist);
头插就成功了。
单链表的尾删
尾删的思路:
定义一个tail指针,找到尾。直接判断tail->next是不是为空,为空就结束循环。我们直接释放tail->next->next,在把tail->next=NULL.还有一个结点的情况,释放然后置空就可以了。
void SListPopBack(SListNode** pplist)
{
assert(pplist);
assert(*pplist);//链表为空不能尾删
if ((*pplist)->next==NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SListNode* tail = *pplist;
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next->next);
tail->next = NULL;
}
}
测试一下
SListPopBack(&plist);
SListPopBack(&plist);
SListPrint(plist);
单链表的头删
头删:定义一个next指针先保存d1->next,在让plist指向d2,如果不保存就先释放d1就找不到d2了。
void SListPopFront(SListNode** pplist)
{
assert(pplist);
assert(*pplist);//链表为空就不能删了
SListNode* next = (*pplist)->next;
free(*pplist);
(*pplist) = next;
}
SListPopFront(&plist);
SListPrint(plist);
-1就删除成功了。
单链表的查找及修改
查找:直接遍历一遍
//单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
SListNode *cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
我们找到的话就可以修改了
SListNode* pos = SListFind(plist,2);
if (pos)
{
printf("找到了\n");
}
else
{
printf("没找到\n");
}
pos->data = 20;//修改
SListPrint(plist);
我们找一下2,并修改为20
单链表在pos位置之后插入值
将newnode指向d3,再将pos指向newnode
void SlistInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode *newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
我们测试在3的后面插入30
pos = SListFind(plist, 3);
if (pos)
{
SlistInsertAfter(pos, 30);
}
SListPrint(plist);
就成功插入30了。
单链表在pos位置之后插入值
搞个next来保存pos->next->next,在释放掉next.
void SlistEraseAfter(SListNode* pos)
{
assert(pos);
SListNode *next = pos->next;
pos->next = next->next;
free(next);
next = NULL;
}
测试一下把1后的删除
pos = SListFind(plist, 1);
if (pos)
{
SListEraseAfter(pos);
}
SListPrint(plist);
之前的20就删除成了。
本篇的单链表就结束了!