提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
讲解单链表的使用,用C语言实现。
一、链表是什么?
1.链表定义:链表是一种数据结构,在物理存储结构上是非连续的,在逻辑结构上通过指针链接实现连续性。链表和顺序表相比,具有按需申请释放空间和不需要挪动数据的优点。
2.链表基本结构
typedef int SLTdatatype;
typedef struct SLTnode
{
SLTdatatype value; //数据
struct SLTnode* next; //结构体指针,指向下一个结构体或null
}SLTnode;
链表就是由这样一个个结构体链接而成的。
二、链表基本操作
1.结点创建
SLTnode* BuySLTnode(SLTDatatype x)
{
SLTnode* newnode=(SLTnode*)malloc(sizeof(SLTnode));
if(newnode==NULL)
{
perror("malloc fail\n");
exit(-1);
}
else
newnode->data=x;
newnode->next=NULL;
return newnode;
}
该函数负责创建结点,返回一个指向结点的指针。
2.创建简单链表
代码如下:
SLTnode* CreatListnode(int n)
{ SLTnode* phead=NULL,*ptail=NULL;
for(int i=0;i<10;i++)
{
SLTnode* newnode=BuySLTnode(i); //创建结点
if(phead==NULL)
{
phead=ptail=newnode; //第一个结点
}
else
{
ptail->next=newnode;
ptail=newnode;
}
return phead;
}
顺序表最重要的是结构,而链表最重要的就是头,所以在创建链表的时候要保护好头,即第一个结点,可以看到,代码没有直接对头进行操作,这样可以避免内存泄漏。
3.读链表
代码如下:
void PrintListnode(SLTnode* phead)
{
while(phead!=Null)
{
SLTnode* cur=phead; //没有直接对phead操作
printf("%d->"cur->data);
cur=cur->next;
}
printf("Null\n");
}
4.单链表尾插尾删
void PushBack(SLTnode** pphead,SLTDatatype x)
{
STLnode* newnode=BuySTLnode(x);
if(*pphead==NULL) //链表为空
{*pphead=newnode;}
else
tail=*pphead; //链表不为空
while(tail->next)
{
tail=tail->next;
}
tail->next=newnode;
}
void popBack(SLTnode** pphead)
{
assert(*pphead);
SLTnode* tail=*pphead;
if(tail->next==NULL)
{free(tail);
tail=NULL;}
while(tail->next->next)
{
tail=tail->next;
}
free(tail->next);
tail->next=NULL;
}
易错点:这里要用到二级指针,因为当链表为空时,需要改变头指针,所以要传指针的地址,形参用二级指针,也可以不传二级指针,函数用返回值。当链表不为空,改变的是结构体,只要用结构体指针就可以了。
5.单链表头插头删
void pushfront(SLTnode** pphead,SLTdatatype x) //同样用到了二级指针
{
SLTnode* newnode=BuySLTnode(x);
newnode->next=*pphead;
*pphead=newnode;
}
void popfront(SLTnode** pphead)
{
assert(*pphead);
SLTnode* next=(*pphead)->next;
free(*pphead);
*pphead=next;
}
相比尾插尾删,单链表用头插头删更加简单,不用考虑链表是否为空。
6.指定位置的插入
void SLTInsertAfter(SLTnode* pos,SLTdatatype x) //在pos位置后面插入
{
assert(pos);
SLTnode* newnode=BUYnode(x);
newnode->next=pos->next;
pos->next=newnode;
}
void SLTInsert(SLTnode** pphead,SLTnode* pos,SLTdatatype x) //在pos位置前面插入
{
assert(pos);
if(pos==*pphead)
{
pushfront(pphead,x);
}
else
{
SLTnode*prev=*pphead;
while(prev->next!=pos)
{prev=prev->next;}
SLTnode*newnode=BUYnode(x);
prev->next=newnode;
newnode->next=pos;
}
}
7.指定位置的删除
void SLTEraseAfter(SLTnode** pphead,SLTnode* pos) //删除pos位置后面
{ assert(pos);
if (pos->next == NULL)
{
return;
}
SListNode* next = pos->next;
pos->next = next->next;
free(next);
}
void SLTErase(SLTnode** pphead,STLnode* pos)
{
assert(pos);
if (*pphead == pos)
{
SListPopFront(pphead);
}
else
{
SListNode* pre = *pphead;
while (pre->next != pos)
{
pre = pre->next;
}
pre->next = pos ->next;
free(pos);
}
8.链表查找
SLTnode* SLTFind(SLTnode*phead,SLTdatatype x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
9.链表销毁
void SLTDestory(SLTnode** pphead)
{
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
free(*pphead);
*pphead = NULL;
}
10.完整代码
头文件
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
SListNode* Createlist(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
SListNode* SListFind(SListNode* plist, SLTDateType x);
//在pos位置之前插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);
void SListInsert(SListNode** pphead,SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos);
//删除pos地址的节点
void SListErase(SListNode** pphead,SListNode* pos);
// 单链表的销毁
void SListDestroy(SListNode* *plist);
函数实现
#include"slist.h"
SListNode* BuySListNode(SLTDateType x)
{
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
if (newnode==NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
SListNode* Createlist(SLTDateType x)
{
SListNode* phead=NULL,*ptail = NULL;
for (int i = 0; i < x; i++)
{
SListNode* newnode = BuySListNode(i);
if (phead == NULL)
{
ptail = phead = newnode;
}
else
{
ptail->next = newnode;
ptail = newnode;
}
}
return phead;
}
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur)
{
printf("%d->",cur->data);
cur = cur->next;
}
printf("NULL\n");
}
void SListPushBack(SListNode** pplist, SLTDateType x) //尾插
{
SListNode* newnode = BuySListNode(x);
if (*pplist == NULL)
{
*pplist = newnode;
}
else
{
SListNode* tail = *pplist;
while (tail->next)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SListPopBack(SListNode** pplist) //尾删
{
assert(*pplist);
if ((*pplist)->next==NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SListNode* newnode = *pplist;
while (newnode->next->next)
{
newnode = newnode->next;
}
free(newnode->next);
newnode->next = NULL;
}
}
void SListPushFront(SListNode** pplist, SLTDateType x) //头插
{
SListNode* newnode = BuySListNode(x);
newnode->next = *pplist;
*pplist = newnode;
}
void SListPopFront(SListNode** pplist) //头删
{
assert(*pplist);
SListNode* newnode = ((*pplist)->next);
free(*pplist);
*pplist = newnode;
}
SListNode* SListFind(SListNode* plist, SLTDateType x) //单链表查找
{
SListNode* cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void SListInsertAfter(SListNode* pos, SLTDateType x) //在pos位置后面插入
{
assert(pos);
SListNode* newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SListInsert(SListNode**pphead,SListNode*pos,SLTDateType x) //在pos位置前面插入x
{
assert(pos);
if (*pphead == pos)
{
SListPushFront(pphead, x);
}
else
{
SListNode* newnode = BuySListNode(x);
SListNode* pre = *pphead;
while (pre->next != pos)
{
pre = pre->next;
}
pre->next = newnode;
newnode->next = pos;
}
}
void SListEraseAfter(SListNode* pos) //在pos位置后面删除
{
assert(pos);
if (pos->next == NULL)
{
return;
}
SListNode* next = pos->next;
pos->next = next->next;
free(next);
}
void SListErase(SListNode**pphead,SListNode* pos) //在pos位置删除
{
assert(pos);
if (*pphead == pos)
{
SListPopFront(pphead);
}
else
{
SListNode* pre = *pphead;
while (pre->next != pos)
{
pre = pre->next;
}
pre->next = pos ->next;
free(pos);
}
}
void SListDestroy(SListNode** plist) //链表销毁
{
SListNode* cur = *plist;
while (cur)
{
SListNode* next = cur->next;
free(cur);
cur = next;
}
free(*plist);
*plist = NULL;
}
总结
萌新blog,很多地方还有不足,此博客更多的是记录自己学习的过程。