目录
单链表介绍
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的。
单链表主要就是逻辑结构和物理结构
每一个节点都是一个结构体,存放的是一个值和一个地址,这个值由自己决定,地址存放的是下一个节点的地址或者是NULL,这样就可以将一个个单独的节点结构体通过结构体嵌套的方式来链接起来,构成单链表。物理结构可以更加直观的表示其结构。
图1(逻辑结构)
图2(物理结构)
代码实现
1.头文件内容
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLTDataType; //重命名数据类型,方便修改
typedef struct SLTNode //重命名节点类型
{
SLTDataType data;
struct SLTNode* next; //结构体的嵌套使得链表链接
}SLTNode;
//打印
void SListPrint(SLTNode* phead);
//申请节点
SLTNode* BuyListNode(SLTDataType x);
//尾插
void SListPushBack(SLTNode** pphead,SLTDataType x);
//头插
void SListPushFront(SLTNode** pphead, SLTDataType x);
//头删
void SListPopFront(SLTNode** pphead);
//尾删
void SListPopBack(SLTNode** phead);
//查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x);
//在pos位置之前去插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos,SLTDataType x);
//删除
void SListErase(SLTNode** pphead, SLTNode* pos);
//销毁
void SListDestory(SLTNode** pphead);
2.函数具体操作
对于有些函数例如这里的插入需要传二级指针,原因是形参是实参的拷贝,因为参数和函数主体中都是一级指针所以改变之后到了main函数中是没有用的,就像交换两个值需要传一级指针是一样的,但是这里的已经是一级指针实现函数了,所以传参需要用二级指针,也需要用二级指针来接收。
1.打印
SList.h
void SListPrint(SLTNode* phead);
SList.c
void SListPrint(SLTNode* phead)
{
SLTNode* cur = phead; //创建一个结构体指针和头节点指向内容一样
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next; //对整个链表遍历
}
printf("NULL\n");
}
2.申请节点
SList.h
SLTNode* BuyListNode(SLTDataType x);
SList.c
SLTNode* BuyListNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//动态内存申请一个结构体节点
newnode->data = x; //data值为x
newnode->next = NULL; //next先置为NULL
return newnode;
}
3.尾插
SList.h
void SListPushBack(SLTNode** pphead, SLTDataType x);
SList.c
void SListPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead!=NULL);//断言判断pphead
SLTNode* newnode = BuyListNode(x); //申请一个节点
if (*pphead == NULL) //判断链表是否为空,插入方式就不同
{
*pphead = newnode;
}
else
{
// 找尾
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next; //遍历尾节点
}
tail->next = newnode;
}
}
4.头插
SList.h
void SListPushFront(SLTNode** pphead, SLTDataType x);
SList.c
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = BuyListNode(x);//申请节点
newnode->next = *pphead;
*pphead = newnode;
}
5.头删
SList.h
void SListPopFront(SLTNode** pphead);
SList.c
void SListPopFront(SLTNode** pphead)
{
assert(*pphead != NULL);
SLTNode* next = (*pphead)->next; //这里*和->都是解引用操作,需要用括号确定优先级
free(*pphead);
*pphead = next;
}
6.尾删
SList.h
void SListPopBack(SLTNode** pphead);
SList.c
void SListPopBack(SLTNode** pphead)
{
assert(*pphead != NULL);
if ((*pphead)->next == NULL) //判断是否是一个节点
{
free(*pphead);
*pphead = NULL;
}
else // 两个节点以上的情况
{
SLTNode* tail = *pphead;
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}
test.c
//头插尾插 头删尾删
void Test1()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPrint(plist);
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPrint(plist);
SListPopBack(&plist);
SListPopBack(&plist);
SListPrint(plist);
SListPopFront(&plist);
SListPopFront(&plist);
SListPrint(plist);
}
int main()
{
Test1();
return 0;
}
运行结果
7.查找
SList.h
SLTNode* SListFind(SLTNode* phead, SLTDataType x);
SList.c
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
test.c
void Test2()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPushBack(&plist, 3);
SListPrint(plist);
SLTNode* pos = SListFind(plist, 3); //查找值为3的节点
int i = 1;
while (pos) //可以将链表中的3都找到,并且打印出来
{
printf("第%d个pos节点:%p->%d\n", i++, pos, pos->data);
pos = SListFind(pos->next, 3);
}
//修改
pos = SListFind(plist, 2);
if (pos)
{
pos->data = 20; //先用查找函数找到这个值在将其data值改为要修改的值
}
SListPrint(plist);
}
8.插入
SList.h
//在pos位置之前去插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
SList.c
//在pos位置之前去插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
SLTNode* newnode = BuyListNode(x);
//链表为空相当于头插
if (*pphead == pos)
{
newnode->next = *pphead;
*pphead = newnode;
}
else
{
//先要找到pos的前一个位置
SLTNode* posPrew = *pphead;
while (posPrew->next != pos)
{
posPrew = posPrew->next;//通过pos前一个位置posPrew来实现对pos位置的操作
}
posPrew->next = newnode;
newnode->next = pos;
}
}
test.c
void Test3()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPrint(plist);
SLTNode* pos = SListFind(plist,2);
if (pos)
{
SListInsert(&plist, pos, 10);
}
SListPrint(plist);
9.删除
SList.h
void SListErase(SLTNode** pphead, SLTNode* pos);
SList.c
void SListErase(SLTNode** pphead, SLTNode* pos)
{
if (*pphead = pos) //这里判断如果只有一个节点的一种情况
{
*pphead = pos->next;
free(pos);
pos = NULL;
}
else
{
SLTNode* prev = *pphead; //找到pos前面的一个节点来对pos实现删除
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
test.c
void Test3()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPrint(plist);
SLTNode* pos = SListFind(plist,2);
if (pos)
{
SListInsert(&plist, pos, 10);
}
SListPrint(plist);
SListErase(&plist, plist);
SListPrint(plist);
}
int main()
{
Test1();
//Test2();
//Test3();
return 0;
}
插入删除的运行结果
10.销毁
SList.h
void SListDestory(SLTNode** pphead);
SList.c
void SListDestory(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}
全部代码实现
SList.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLTDataType;
typedef struct SLTNode
{
SLTDataType data;
struct SLTNode* next;
}SLTNode;
//打印
void SListPrint(SLTNode* phead);
//申请节点
SLTNode* BuyListNode(SLTDataType x);
//尾插
void SListPushBack(SLTNode** pphead,SLTDataType x);
//头插
void SListPushFront(SLTNode** pphead, SLTDataType x);
//头删
void SListPopFront(SLTNode** pphead);
//尾删
void SListPopBack(SLTNode** phead);
//查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x);
//在pos位置之前去插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos,SLTDataType x);
//删除
void SListErase(SLTNode** pphead, SLTNode* pos);
//销毁
void SListDestory(SLTNode** pphead);
SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
//打印
void SListPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
//申请节点
SLTNode* BuyListNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//尾插
void SListPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead!=NULL);
SLTNode* newnode = BuyListNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
// 找尾
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
//头插
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = BuyListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
//头删
void SListPopFront(SLTNode** pphead)
{
assert(*pphead != NULL);
SLTNode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
//尾删
void SListPopBack(SLTNode** pphead)
{
assert(*pphead != NULL);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* tail = *pphead;
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}
//查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
//在pos位置之前去插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
SLTNode* newnode = BuyListNode(x);
//链表为空相当于头插
if (*pphead == pos)
{
newnode->next = *pphead;
*pphead = newnode;
}
else
{
//先要找到pos的前一个位置
SLTNode* posPrew = *pphead;
while (posPrew->next != pos)
{
posPrew = posPrew->next;
}
posPrew->next = newnode;
newnode->next = pos;
}
}
//删除
void SListErase(SLTNode** pphead, SLTNode* pos)
{
if (*pphead = pos)
{
*pphead = pos->next;
free(pos);
pos = NULL;
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
//销毁
void SListDestory(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
//头插尾插 头删尾删
void Test1()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPrint(plist);
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPrint(plist);
SListPopBack(&plist);
SListPopBack(&plist);
SListPrint(plist);
SListPopFront(&plist);
SListPopFront(&plist);
SListPrint(plist);
}
//查找 修改
void Test2()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPushBack(&plist, 3);
SListPrint(plist);
SLTNode* pos = SListFind(plist, 3);
int i = 1;
while (pos)
{
printf("第%d个pos节点:%p->%d\n", i++, pos, pos->data);
pos = SListFind(pos->next, 3);
}
//修改
pos = SListFind(plist, 2);
if (pos)
{
pos->data = 20;
}
SListPrint(plist);
}
//插入 删除
void Test3()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPrint(plist);
SLTNode* pos = SListFind(plist,2);
if (pos)
{
SListInsert(&plist, pos, 10);
}
SListPrint(plist);
SListErase(&plist, plist);
SListPrint(plist);
}
int main()
{
//Test1();
//Test2();
Test3();
return 0;
}