目录
1单链表的结构
单链表的逻辑结构是线性的;
物理结构不一定是线性的。
2单链表的实现
2.1单链表的结点结构
结点包括要储存的数据,以及指向下一个结点的指针。
代码如下:
struct SLTnode {
sltdata data;
struct SLTnode* next;
};
typedef struct SLTnode slt;
2.2单链表的插入
在进行插入操作的时候,需要用malloc函数创建新结点,后续会经常使用,因此直接将该操作封装成一个函数。
代码如下:
//创建新节点
slt* sltbuynode(sltdata x)
{
slt* node = (slt*)malloc(sizeof(sltdata));
if (node == NULL)
{
perror("buynode fail");
exit(1);
}
node->data = x;
node->next = NULL;
return node;
}
2.2.1首插
思路:先创建一个新结点,将新结点next指向头结点,再让新结点成为新的头结点。
思考:为什么要用2级指针?
原因如下:test函数中list指针初始化为NULL,在插入函数中,如果传入的是一级指针phead,此时phead是形参,对phead修改不会影响到实参list。
除了插入操作需要2级指针,后面很多地方都要使用2级指针。
代码如下:
void sltpushfront(slt** pphead, sltdata x)
{
assert(pphead);
slt* newnode = sltbuynode(x);
newnode->next = *pphead;
*pphead = newnode;
}
测试:
2.2.2尾插
思路:创建新结点,若链表为空,则新结点为头结点;
若不为空,while循环找到尾节点,将新结点置于尾结点后。
void sltpushback(slt** pphead, sltdata x)
{
assert(pphead);
slt* newnode = sltbuynode(x);
if (*pphead)
{
*pphead = newnode;
}
else
{
slt* pcur = *pphead;
while (pcur->next)
{
pcur = pcur->next;
}
pcur->next = newnode;
}
}
测试:
2.3单链表的删除
2.3.1头删
思路:
先将next指针记录头结点的next;free销毁头结点;再将头结点指向next指针所指向的。
代码如下:
void sltpopfront(slt** pphead)
{
assert(pphead&&*pphead);
slt* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
测试:
2.3.2尾删
思路:如果链表只有一个结点,直接free,再置为NULL;
如果大于一个结点,找到尾结点ptail和尾结点的前一个结点prev,将prev的next置为NULL,将ptail结点free,再置为NULL。
代码如下:
void sltpopback(slt** pphead)
{
assert(pphead && *pphead);
if (!(*pphead)->next)
{
free(*pphead);
*pphead = NULL;
}
else
{
slt* ptail = *pphead;
slt* prev = NULL;
while (ptail->next)
{
prev = ptail;
ptail = ptail->next;
}
prev->next= NULL;
free(ptail);
ptail = NULL;
}
}
测试:
2.4查找值为x的结点
slt* sltfind(slt* phead, sltdata x)
{
assert(phead);
slt* pcur = phead;
while (pcur)
{
if (pcur->data == x)
return pcur;
pcur = pcur->next;
}
return NULL;
}
测试:
2.5指定位置的插入
2.5.1指定位置前
思路:要在pos位置前进行插入,就要找到pos前的一个结点,如果pos结点是头结点,没有前结点,则进行一次头插;
否则找到pos的前一个结点,进行插入。
代码如下:
void sltinsert(slt** pphead,slt*pos,sltdata x)
{
assert(pphead);
slt* newnode = sltbuynode(x);
if (*pphead == pos)
{
newnode->next=pos;
*pphead = newnode;
}
else
{
slt* pcur = *pphead;
while (pcur->next != pos)
{
pcur = pcur->next;
}
newnode->next = pcur->next;
pcur->next = newnode;
}
}
测试:
2.5.2指定位置后的插入
思路:比较简单,创建新结点,将新结点的next指向pos的next,再将pos的next指向新结点。
代码如下:
void sltinsertafter(slt** pphead, slt* pos, sltdata x)
{
assert(pphead);
slt* newnode = sltbuynode(x);
newnode->next = pos->next;
pos->next = newnode;
}
测试:
2.6指定位置的删除
2.6.1指定位置的删除
思路:要找到pos的前一个结点,因此又要分成两种情况:pos为头结点,就没有前一个结点,直接头删;
否则,找到pos的前一个结点,将前一个结点的next指向pos的next,销毁pos,在置为NULL。
代码如下:
void slterase(slt** pphead, slt* pos)
{
assert(pphead && *pphead);
assert(pos);
if (*pphead == pos)
{
sltpopfront(pphead);
}
else
{
slt* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
测试:
2.6.2指定位置后的删除
思路:先将pos的next结点用del记录下来,再将pos的next指向next的next,实现删除,再对del进行销毁,再置为NULL。
代码如下:
void slteraseafter(slt* pos)
{
assert(pos && pos->next);
slt* del = pos->next;
pos->next = pos->next->next;
free(del);
del = NULL;
}
测试:
2.7销毁链表
思路:pcur循环遍历链表,用next结点记录pcur的下一个结点,销毁pcur结点,pcur在指向next,最后再将链表置为空。
代码如下:
void sltdestroy(slt** pphead)
{
assert(pphead && *pphead);
slt* pcur = *pphead;
while (pcur)
{
slt* next = pcur->next;
free(pcur);
pcur = next;
}
*pphead = NULL;
}
测试:
3单链表的总代码
3.1SLTNode.h
#include<assert.h>
#include<stdlib.h>
#include<stdio.h>
typedef int sltdata;
struct SLTnode {
sltdata data;
struct SLTnode* next;
};
typedef struct SLTnode slt;
void sltprintf(slt*phead);
void sltpushback(slt** pphead,sltdata x);
void sltpushfront(slt** pphead, sltdata x);
void sltpopfront(slt** pphead);
void sltpopback(slt** pphead);
slt* sltfind(slt* phead,sltdata x);
void sltinsert(slt** pphead, slt* pos, sltdata x);
void sltinsertafter(slt* pos, sltdata x);
void slterase(slt** phead, slt* pos);
void slteraseafter(slt* pos);
void sltdestroy(slt** pphead);
3.2SLTNode.c
#include"SLTNode.h"
//创建新节点
slt* sltbuynode(sltdata x)
{
slt* node = (slt*)malloc(sizeof(sltdata));
if (node == NULL)
{
perror("buynode fail");
exit(1);
}
node->data = x;
node->next = NULL;
return node;
}
//打印链表
void sltprintf(slt* phead)
{
slt* pcur = phead;
while (pcur)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("NULL\n");
}
//插入
void sltpushback(slt** pphead, sltdata x)
{
assert(pphead);
slt* newnode = sltbuynode(x);
if (*pphead==NULL)
{
*pphead = newnode;
}
else
{
slt* pcur = *pphead;
while (pcur->next)
{
pcur = pcur->next;
}
pcur->next = newnode;
}
}
void sltpushfront(slt** pphead, sltdata x)
{
assert(pphead);
slt* newnode = sltbuynode(x);
newnode->next = *pphead;
*pphead = newnode;
}
//删除
void sltpopfront(slt** pphead)
{
assert(pphead&&*pphead);
slt* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
void sltpopback(slt** pphead)
{
assert(pphead && *pphead);
if (!(*pphead)->next)
{
free(*pphead);
*pphead = NULL;
}
else
{
slt* ptail = *pphead;
slt* prev = NULL;
while (ptail->next)
{
prev = ptail;
ptail = ptail->next;
}
prev->next= NULL;
free(ptail);
ptail = NULL;
}
}
//查找
slt* sltfind(slt* phead, sltdata x)
{
assert(phead);
slt* pcur = phead;
while (pcur)
{
if (pcur->data == x)
return pcur;
pcur = pcur->next;
}
return NULL;
}
//指定位置的插入
void sltinsert(slt** pphead,slt*pos,sltdata x)
{
assert(pphead);
slt* newnode = sltbuynode(x);
if (*pphead == pos)
{
newnode->next=pos;
*pphead = newnode;
}
else
{
slt* pcur = *pphead;
while (pcur->next != pos)
{
pcur = pcur->next;
}
newnode->next = pcur->next;
pcur->next = newnode;
}
}
void sltinsertafter(slt* pos, sltdata x)
{
assert(pos);
slt* newnode = sltbuynode(x);
newnode->next = pos->next;
pos->next = newnode;
}
//指定位置的删除
void slterase(slt** pphead, slt* pos)
{
assert(pphead && *pphead);
assert(pos);
if (*pphead == pos)
{
sltpopfront(pphead);
}
else
{
slt* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
void slteraseafter(slt* pos)
{
assert(pos && pos->next);
slt* del = pos->next;
pos->next = pos->next->next;
free(del);
del = NULL;
}
//销毁链表
void sltdestroy(slt** pphead)
{
assert(pphead && *pphead);
slt* pcur = *pphead;
while (pcur)
{
slt* next = pcur->next;
free(pcur);
pcur = next;
}
*pphead = NULL;
}