前言
单链表的定义和基本操作(增删查改)
单链表定义
链表特性
- 任意物理位置的存储单元来存放数据元素
- 存储单元可以连续,也可以不连续
- 与顺序表不同,链表元素并不一定按顺序排列;链表是根据结点指针来确定元素位置的
链表专有术语
链表结点:由数据域和指针域两部分组成。
数据域:存储元素数值数据
指针域:存储直接后继结点的存储位置(即当前结点的下一个结点的位置)
头指针:是指向链表中头结点的指针
头结点:是在首元结点之前的一个结点;数据域内存储 空表标志和表长信息
首元结点:是链表中存储第一个元素的结点
构造链表
typedef ElemType int; //定义元素类型
typedef struct LNode{
ElemType data;
struct LNode* next;
}LNode,*LinkList;
LinkList L;
单链表的基本操作
链表的初始化
构造一个带头结点的空的单链表:
新建头结点,将头指针指向头结点
将头结点的next指针置为空
bool InitList(LinkList &L)
{
L=new LNode;
if(!L) return false; //如果头结点创建失败,返回false
L->next=null; //初始化头结点next指针
return true;
}
小提示:一个链表的某个结点一定是由某个指针表示的,若离开这个指针那么这个结点将不存在与该链表。
判断链表是否为空
空表:表中无元素,只存在头指针和头结点
bool ListEmpty(LinkList &L)
{
if(L->next) return false;
else return true; //链表为空
}
销毁单链表
遍历整个链表,将所有结点删除(释放物理空间)
bool DestroyList(LinkList &L)
{
//创建一个结点指针p,用来删除链表每个结点
ListNode *p;
while(L)
{
//记下当前结点
p=L;
//访问下一个结点
L=L->next;
//删除当前结点
Delete p;
}
if(!p) return true;
return false;
}
求单链表长度
int ListLength(LinkList L)
{
ListNode* p; //p指针访问所有结点
p=L->next; //p指向首元结点
int len=0;
while(p)
{
p=p->next;
len++;
}
return len;
}
链表元素取值
取出第i个元素的值
时间复杂度为O(N)
从首结点开始顺链扫描,用指针p指向当前扫描的结点
ret记录累计扫描的节点数,ret初始值为1
指针p指向下一个结点,ret+=1
假设取第i个元素,当ret等于i时,p指向的结点的元素就是目标元素
void GetElem(LinkList L,int i,ElemType &e)
{
p=L->next;
int ret=1;
while(ret<i && p)
{
ret++;
p=p->next;
}
//第i个元素不存在
if(!p || ret<i) return false;
e=p->data;
return true;
}
链表元素查找
查找目标元素
时间复杂度为O(N)
从第一个结点开始,依次与目标元素e比较
指针p指向当前结点,p不断向后移动,直到找到e为止
找到目标元素则返回p,否则返回null
LNode* SearchElem(LinkList L,ElemType &e)
{
LNode* p=L->next;
while(p && p->data!=e)
{
p=p->next;
}
return p; //返回指针p,没找到目标就是null
}
链表结点插入(后插)
时间复杂度为O(1)
设待插入结点为e,插在p结点之后
先连接e结点与p的下一个结点,再连接p与e
如果反过来操作,会出现找不到p的下一个结点的情况;也就是说不能破坏p与p->next的联系
bool InsertElem(LinkList &L,LNode* p,LNode* e)
{
if(!e || !p) return false; //e和p不能为空
e->next=p->next;
p->next=e;
return true;
}
链表结点删除
时间复杂度为O(N)
删除第i个位置的结点
指针p遍历链表,找第i-1个位置的结点
p最终指向i-1位置的结点,再将p与p的next的next结点连接
bool DeleteElem(LinkList &L,int i)
{
LNode *p=L;
int ret=1;
//找到第i-1个结点
while(ret<i)
{
p=p->next;
ret++;
}
//备份第i个位置的结点
LNode* fp=p->next;
//连接i-1与i+1位置的结点
p->next=p->next->next;
//删除第i个位置的结点
free(fp);
if(!fp) return true;
return false;
}
链表结点前插
时间复杂度为O(N)
在p结点之前插入结点e
指针cur遍历链表,找到p结点前一个结点
先连接e结点与p的下一个结点,再连接p与e
bool InsertElem(LinkList &L,LNode* p,LNode* e)
{
if(!p || !e) return false; //p和e不能为空
LNode cur=L->next;
//找到p结点前一个结点
while(cur->next!=p)
{
cur=cur->next;
}
e->next=p;
cur->next=e;
return true;
}
总结
本文简单介绍了单链表的定义和基本操作(增删查改)
文章到这结束啦,感谢阅读~
如果文章的论述或代码等出现错误,欢迎前来指正!
如果你觉得文章写的还不错,记得点赞收藏评论三连~ ❤