单链表
插入和删除结点的操作
1)插入结点
在单链表中插入一个新结点需要找到插入后的前驱结点
代码描述:
s->next=p->next;
p->next=s;
2)删除结点
需要找到其前驱结点
代码描述
p->next=p->next->next
一般情况下,删除结点后还需要释放其内存空间
q=p->next; //q临时保存被删结点
p->next=q->next; //从链表中删除结点q
free(q); //释放结点q的空间
单链表基本运算
#include<stdio.h>
#include<malloc.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data; //存放元素值
struct LNode *next; //指向后继结点
} LinkNode; //单链表结点类型
//头插法:从一个空表开始依次读取数组a中的元素,生成一个新结点(由s指向它),
//将读取的数组元素存放到该结点的数据域中,再将其插入到当前链表的表头上(即头结点之后)
void CreateListF(LinkNode *&L,ElemType a[],int n)
{
LinkNode *s;
L=(LinkNode *)malloc(sizeof(LinkNode));
L->next=NULL; //创建头结点,其next域置为NULL
for(int i=0;i<n;i++) //循环建立数据结点s
{
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=a[i]; //创建数据结点s
s->next=L->next; //将结点s插入到原首结点之前、头结点之后
L->next=s;
}
}
//尾插法:从一个空表开始依次读取数组a中的元素,生成一个新结点s,将读取的数组元素
//存放到该结点的数据域中,再将其插入到当前链表的表尾上
void CreateListR(LinkNode *&L,ElemType a[],int n)
{
LinkNode *s,*r;
L=(LinkNode *)malloc(sizeof(LinkNode)); //创建头结点
r=L; //r始终指向尾结点,初始时指向头结点
for(int i=0;i<n;i++) //循环建立数据结点
{
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=a[i]; //创建数据结点s
r->next=s; //将结点s插入结点r之后
r=s;
}
r->next=NULL; //尾结点的next域置为NULL
}
//初始化线性表:建立一个空的单链表
void InitList(LinkNode *&L)
{
L=(LinkNode *)malloc(sizeof(LinkNode));
L->next=NULL; //创建头结点,其next置域为NULL
}
//销毁线性表:释放单链表L占用的内存空间,即逐一释放全部结点的空间
//让pre、p指向两个相邻的结点(初始时pre指向头结点,p指向首结点)
void DestroyList(LinkNode *&L)
{
LinkNode *pre=L,*p=L->next; //pre指向结点p的前驱结点
while(p!=NULL) //扫描单链表L
{
free(pre); //释放pre结点
pre=p; //pre、p同步后移一个结点
p=pre->next;
}
free(pre); //循环结束时p为NULL,pre指向尾结点,释放它
}
//判断线性表是否为空表:单链表L中没有数据结点时返回真,否者返回假
bool ListEmpty(LinkNode *L)
{
return(L->next==NULL);
}
//求线性表的长度:返回单链表L中数据结点的个数
//让P指向头结点,n用来累计数据结点个数(初始值为0)
//当p不为空时循环:n增1,p指向下一个结点。循环结束后返回n。
int ListLength(LinkNode *L)
{
int n=0;
LinkNode *p=L; //p指向头结点,n置为0(即头结点的序号为0)
while(p->next!=NULL)
{
n++;
p=p->next;
}
return(n); //循环结束,p指向尾结点,其序号n为结点个数
}
//输出线性表:逐一扫描单链表L的每个数据结点,并显示各结点的data域置
void DispList(LinkNode *L)
{
LinkNode *p=L->next; //p指向首结点
while(p!=NULL) //p不为NULL,输出p结点的data域
{
printf("%d",p->data);
p=p->next; //p移向下一个结点
}
printf("\n");
}
//求线性表中的某个数据元素值:在单链表L中从头开始找到第i个结点,若存在第i个数据结点,
//则将其data域值赋给变量e
//让p指向头结点,j用来累计遍历过的数据结点个数(初始值为0),当j<i且p不为空时循环:
//j增1,p指向下一个结点。循环结束后有两种情况,若p为空,表示单链表L中没有第i个数据
//结点(参数i错误),返回false;否则找到,提取值并返回true
bool GetElem(LinkNode *L,int i,ElemType &e)
{
int j=0;
LinkNode *p=L; //p指向头结点,j置为0(即头结点的序号为0)
if(i<=0)return false; //i值错误返回假
while(j<i&&p!=NULL) //找第i个结点p
{
j++;
p=p->next;
}
if(p==NULL) //不存在第i个数据结点,返回false
return false;
else //存在第i个数据结点,返回true
{
e=p->data;
return true;
}
}
//按元素值查找:在单链表L中从头开始找第一个值域与e相等的结点,若存在这样的结点,
//则返回逻辑序号,否则返回0
int LocateElem(LinkNode *L,ElemType e)
{
int i=1;
LinkNode *p=L->next; //p指向首结点,i置为1(即首结点的序号为1)
while(p!=NULL&&p->data!=e) //查找data值为e的结点,其序号为i
{
p=p->next;
i++;
}
if(p==NULL) //不存在值为e的结点,返回0
return(0);
else //存在值为e的结点,返回其逻辑序号i
return(i);
}
//插入数据元素:先在单链表L中找到第i-1个结点,由p指向它
//若存在这样的结点,将值为e的结点(s指向它)插入到p所指结点的后面
bool ListInsert(LinkNode *&L,int i,ElemType e)
{
int j=0;
LinkNode *p=L,*s; //p指向头结点,j置为0(即头结点的序号为0)
if(i<=0)return false; //i错误返回false
while(j<i-1&&p!=NULL) //查找第i-1个结点p
{
j++;
p=p->next;
}
if(p==NULL) //未找到第i-1个结点,返回false
return false;
else //找到第i-1个结点p,插入新结点并返回true
{
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=e; //创建新结点s,其data域置为e
s->next=p->next; //将结点s插入到结点p之后
p->next=s;
return true;
}
}
//删除数据元素:先在单链表L中找到第i-1个结点,由p指向它。
//若存在这样的结点,且也存在后继结点(由q指向它),则删除q所指的结点,返回true
//否则返回false,表示参数i错误
bool ListDelete(LinkNode *&L,int i,ElemType &e)
{
int j=0;
LinkNode *p=L,*q; //p指向头结点,j置为0(即头结点的序号为0)
if(i<=0)return false; //i错误返回false
while(j<i-1&&p!=NULL) //查找第i-1个结点
{
j++;
p=p->next;
}
if(p==NULL) //未找到第i-1个结点,返回false
return false;
else //找到第i-1个结点p
{
q=p->next; //q指向第i个结点
if(q==NULL) //若不存在第i个结点,返回false
return false;
e=q->data;
p->next=q->next; //从单链表中删除q结点
free(q); //释放q结点
return true; //返回true表示成功删除第i个结点
}
}