作者简介 :RO-BERRY
学习方向:致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持
链表从某种意义上来说就像一个火车一样,有火车头和火车上个各个节点车厢以及火车尾。
链表从某种意义上来说就像一个火车一样,有火车头和火车上个各个节点车厢以及火车尾。
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:
结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现了就知道了。
我们需要多去尝试多文件实现程序,以便以后进行实际化,主要有一个头文件SList.h和两个源文件SList.c(实现链表主要功能)和test.c(执行测试函数)
#include
#include
#include
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
在一开始主要包含了头文件、类型的定义以及最关键的链表结构体定义,我们定义SLTDataType的作用是,为了方便以后进行更改,我们在之后如果不存储int类型的数据的时候,我们可以直接在一开头对于SLTDataType指向的内容进行修改,即不需要在程序内部每一个int出现都需要进行修改。而结构体名称自然是自取之,因为我们写的是一个单链表,即内容只有一个存储内容data,还有指向下一个结点的结构体指针next。
我们先在SList.h头文件里面进行定义
void SLTPrint(SLTNode* phead); //打印
再在SList.c源文件里进行实现:
void SLTPrint(SLTNode* phead)
{
SLTNode* cur = phead; //将头结点的地址拷贝给cur
while (cur) //cur为NUIL终止
{
printf("%d->", cur->data);
cur = cur->next; //遍历下一个结点
}
printf("NULL\n");
}
我们先在SList.h头文件里面进行定义
SLTNode* BuyListNode(SLTDataType x); //创建新节点
再在SList.c源文件里进行实现:
SLTNode* BuyListNode(SLTDataType x)
{
SLTNode* newnode =(SLTNode*)malloc(sizeof(SLTNode)); //动态开辟空间
if (newnode == NULL) //如果开辟失败
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL; //只是进行创建,next在后面进行赋值,插入链表里,具体问题具体操作
}
我们先在SList.h头文件里面进行定义
void SLTPushBack(SLTNode* phead, SLTDataType x); //尾插
void SLTPushFront(SLTNode** pphead, SLTDataType x); //头插
void SLTPopback(SLTNode** pphead); //尾删
void SLTPopFront(SLTNode* pphead); //头删
再在SList.c源文件里进行实现:
void SLTPushBack(SLTNode** pphead, SLTDataType x) //这里用结构体二级指针改变一级指针
{
SLTNode* newnode = BuyListNode(x);
if (*pphead == NULL) //如果头链表为空
{
*pphead = newnode;
}
else
{
SLTNode* list = *pphead;
while (list->next != NULL) //遍历到最后一个元素
{
list = list->next;
}
list->next = newnode; //改变的是结构体
}
}
void SLTPushFront(SLTNode** pphead, SLTDataType x) //改的是结构体指针
{
SLTNode* newnode = BuyListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SLTPopback(SLTNode** pphead)
{
//1.为空
//2.只有一个结点
//3.一个以上结点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* tailPrev = NULL;
SLTNode* tail = *pphead;
while (tail->next)
{
tailPrev = tail;
tail = tail->next;
}
tailPrev->next = NULL;
free(tail);
// tail = NULL;
}
}
void SLTPopFront(SLTNode** pphead)
{
assert(*pphead);
SLTNode* newhead = (*pphead)->next;
free(*pphead);
*pphead = newhead;
}
我们先在SList.h头文件里面进行定义
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
再在SList.c源文件里进行实现:
SLTNode* SLTFind(SLTNode* phead, SLTDataType x) //查找X
{
SLTNode* cur = phead; //将头结点赋值给cur临时变量
while (cur)
{
if (cur->data == x) //遍历
{
return cur;
}
cur = cur->next;
}
return NULL;
}
我们先在SList.h头文件里面进行定义
void SLTInsert(SLTNode* pphead, SLTNode* pos, SLTDataType x); //在pos之前插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x); //在pos之后插入x
再在SList.c源文件里进行实现:
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) //在pos之前插入x
{
assert(pos);
if (pos == *pphead)
{
SLTPushBack(*pphead,x);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
SLTNode* newnode = BuyListNode(x);
newnode->next = prev->next;
prev -> next = newnode;
}
}
void SLTInsertAfter(SLTNode* pos, SLTDataType x) //在pos之后插入x
{
assert(pos);
SLTNode* newnode = BuyListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
我们先在SList.h头文件里面进行定义
void SLTErase(SLTNode** pphead, SLTNode* pos); //删除pos位置
void SLTEraseAfter(SLTNode* pos); //删除pos的后一个位置
再在SList.c源文件里进行实现:
void SLTErase(SLTNode** pphead, SLTNode* pos)//删除pos位置
{
assert(pos);
if (pos == *pphead)
{
SLTPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
//pos= NULL;
}
}
void SLTEraseAfter(SLTNode* pos) //删除pos的后一个位置
{
assert(pos);
//检查pos是否是尾结点
assert(pos->next);
SLTNode* posNext = pos->next;
pos->next = posNext->next;
free(posNext);
posNext = NULL;
}
#pragma once
#include
#include
#include
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead); //打印
SLTNode* BuyListNode(SLTDataType x); //创建新节点
void SLTPushBack(SLTNode* phead, SLTDataType x); //尾插
void SLTPushFront(SLTNode** pphead, SLTDataType x); //头插
void SLTPopback(SLTNode** pphead); //尾删
void SLTPopFront(SLTNode* pphead); //头删
SLTNode* SLTFind(SLTNode* phead, SLTDataType x); //查找X
void SLTInsert(SLTNode* pphead, SLTNode* pos, SLTDataType x); //在pos之前插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x); //在pos之后插入x
void SLTErase(SLTNode** pphead, SLTNode* pos); //删除pos位置
void SLTEraseAfter(SLTNode* pos); //删除pos的后一个位置
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
void SLTPrint(SLTNode* phead)
{
SLTNode* cur = phead; //将头结点的地址拷贝给cur
while (cur) //cur为NUIL终止
{
printf("%d->", cur->data);
cur = cur->next; //遍历下一个结点
}
printf("NULL\n");
}
SLTNode* BuyListNode(SLTDataType x)
{
SLTNode* newnode =(SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
}
void SLTPushBack(SLTNode** pphead, SLTDataType x) //这里用结构体二级指针改变一级指针
{
SLTNode* newnode = BuyListNode(x);
if (*pphead == NULL) //如果头链表为空
{
*pphead = newnode;
}
else
{
SLTNode* list = *pphead;
while (list->next != NULL) //遍历到最后一个元素
{
list = list->next;
}
list->next = newnode; //改变的是结构体
}
}
void SLTPushFront(SLTNode** pphead, SLTDataType x) //改的是结构体指针
{
SLTNode* newnode = BuyListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SLTPopback(SLTNode** pphead)
{
//1.为空
//2.只有一个结点
//3.一个以上结点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* tailPrev = NULL;
SLTNode* tail = *pphead;
while (tail->next)
{
tailPrev = tail;
tail = tail->next;
}
tailPrev->next = NULL;
free(tail);
// tail = NULL;
}
}
void SLTPopFront(SLTNode** pphead)
{
assert(*pphead);
SLTNode* newhead = (*pphead)->next;
free(*pphead);
*pphead = newhead;
}
SLTNode* SLTFind(SLTNode* phead, SLTDataType x) //查找X
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) //在pos之前插入x
{
assert(pos);
if (pos == *pphead)
{
SLTPushBack(*pphead,x);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
SLTNode* newnode = BuyListNode(x);
newnode->next = prev->next;
prev -> next = newnode;
}
}
void SLTInsertAfter(SLTNode* pos, SLTDataType x) //在pos之后插入x
{
assert(pos);
SLTNode* newnode = BuyListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SLTErase(SLTNode** pphead, SLTNode* pos)//删除pos位置
{
assert(pos);
if (pos == *pphead)
{
SLTPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
//pos= NULL;
}
}
void SLTEraseAfter(SLTNode* pos) //删除pos的后一个位置
{
assert(pos);
//检查pos是否是尾结点
assert(pos->next);
SLTNode* posNext = pos->next;
pos->next = posNext->next;
free(posNext);
posNext = NULL;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
void TestSLTlist1()
{
int n;
printf("请输入链表的长度:\n");
scanf("%d", &n);
printf("请依次输入每个结点的值:\n");
SLTNode* plist = NULL; // 头结点
for (int i = 0; i < n; i++)
{
int val;
scanf("%d", &val);
SLTNode* newnode = BuyListNode(val);
//头插
newnode->next = plist;
plist = newnode;
}
SLTPushBack(&plist, 1000);
SLTPrint(plist);
}
TestSLTlist2() //尾插
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 10);
SLTPushBack(&plist, 1000);
SLTPushBack(&plist, 10000);
SLTPushBack(&plist, 100000);
SLTPushBack(&plist, 1000000);
SLTPrint(plist);
SLTPushFront(&plist, 1);
SLTPushFront(&plist, 2);
SLTPushFront(&plist, 3);
SLTPushFront(&plist, 4);
SLTPushFront(&plist, 5);
SLTPrint(plist);
}
TestSLTlist3()//尾删
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 10);
SLTPushBack(&plist, 1000);
SLTPushBack(&plist, 10000);
SLTPushBack(&plist, 100000);
SLTPushBack(&plist, 1000000);
SLTPrint(plist);
SLTPopback(&plist);
SLTPrint(plist);
SLTPopback(&plist);
SLTPrint(plist);
SLTPopback(&plist);
SLTPrint(plist);
SLTPopback(&plist);
SLTPrint(plist);
}
TestSLTlist4() //头删
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 10);
SLTPushBack(&plist, 1000);
SLTPushBack(&plist, 10000);
SLTPushBack(&plist, 100000);
SLTPushBack(&plist, 1000000);
SLTPrint(plist);
SLTPopFront(&plist);
SLTPrint(plist);
SLTPopFront(&plist);
SLTPrint(plist);
SLTPopFront(&plist);
SLTPrint(plist);
SLTPopFront(&plist);
SLTPrint(plist);
}
TestSLTlist5() //查找测试
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 10);
SLTPushBack(&plist, 1000);
SLTPushBack(&plist, 10000);
SLTPushBack(&plist, 100000);
SLTPushBack(&plist, 1000000);
SLTPrint(plist);
SLTPopFront(&plist);
SLTPrint(plist);
SLTNode* pos= SLTFind(plist, 10);
if (pos)
{
pos->data *= 10;
}
SLTPrint(plist);
}
TestSLTlist6() //前插测试
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 10);
SLTPushBack(&plist, 1000);
SLTPushBack(&plist, 10000);
SLTPushBack(&plist, 100000);
SLTPushBack(&plist, 1000000);
SLTPrint(plist);
SLTPopFront(&plist);
SLTPrint(plist);
SLTNode* pos = SLTFind(plist, 1000);
if (pos)
{
int x;
scanf("%d", &x);
SLTInsert(&plist, pos, x);
}
SLTPrint(plist);
}
TestSLTlist7() //后插测试
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 10);
SLTPushBack(&plist, 1000);
SLTPushBack(&plist, 10000);
SLTPushBack(&plist, 100000);
SLTPushBack(&plist, 1000000);
SLTPrint(plist);
SLTNode* pos = SLTFind(plist, 1000);
if(pos)
{
int x;
scanf("%d", &x);
SLTInsertAfter(pos, x);
}
SLTPrint(plist);
}
TestSLTlist8() //删除测试
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 10);
SLTPushBack(&plist, 1000);
SLTPushBack(&plist, 10000);
SLTPushBack(&plist, 100000);
SLTPushBack(&plist, 1000000);
SLTPrint(plist);
SLTNode* pos = SLTFind(plist, 1000);
if (pos)
SLTErase(&plist, pos);
SLTPrint(plist);
}
TestSLTlist9() //后一个节点删除测试
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 10);
SLTPushBack(&plist, 1000);
SLTPushBack(&plist, 10000);
SLTPushBack(&plist, 100000);
SLTPushBack(&plist, 1000000);
SLTPrint(plist);
SLTNode* pos = SLTFind(plist, 1000);
if (pos)
SLTEraseAfter(pos);
SLTPrint(plist);
}
int main()
{
TestSLTlist9();
return 0;
}