(一)含有头结点单链表的基本操作的实现:(初始化、增、删、改、查,等)
单链表的结构定义:
#include
#include typedef int ElemType; //定义单链表结构 typedef struct LNode{ //声明节点的类型和指向结点的指针类型 ElemType data; //数据域 struct LNode *next; //指针域 }LNode,*LinkList; //重命名为 LNode LinkList为指向LNode的指针类
//注意:
在后续定义一个新的链表时一般表达为: LinkList L ;
定义一个结点指针时一般表达为: LNode *p ;
补充: 关键字typedef --------数据类型重命名
格式: typedef <数据类型> <别名>
函数:malloc---------动态申请内存空间
格式:(Elemtype)malloc(sizeof(Elemtype));
1.单链表的初始化
算法步骤:
1)生成新结点作为头结点,用头指针L指向头结点;
2)将头结点的指针域置空;
//1.初始化,创建头结点
bool InitList(LinkList &L){
L=(LNode *) malloc(sizeof(LNode)); //定义一个新结点作为头结点,用指针L指向头结点
if(L==NULL){ //头结点的指针域包含的是首节点的地址,如果为空则内存不足,分配失败
printf("申请内存空间失败\n");
}
L->next=NULL; //给头指针的指针域置空
return true;
}
2.头插法
算法步骤:
1)从一个空表开始,重复读入数据;
2)生成新结点,将读入的数据存入新结点数据域中;
3)从最后一个结点开始,依次将各结点插入到链表的前端。
//2.采用头插法创建单链表
//单链表建成后,顺序会与自己输入的顺序呈相反的顺序
LinkList List_HeadInsert(LinkList &L){
LNode *s; //定义一个新的结点指针
int x; //定义一个整形变量接收数据
L=(LNode *)malloc(sizeof(LNode)) ; //定义一个新结点作为头结点,用指针L指向头结点
if(L==NULL){ //头结点的指针域包含的是首节点的地址,如果为空则内存不足,分配失败
return false;
}
L->next=NULL; //头结点的指针域设为空,即初始为空链表
scanf("%d",&x); //输入元素值
while(x!=9999){ //当输入9999结束循环
s=(LNode *)malloc(sizeof(LNode)); //创建新的结点s并自动分配内存空间
s->data=x; //把输入的值x赋值给s结点的数据域
s->next=L->next; //进行前插
L->next=s; //将头指针指向新插入的结点S
scanf("%d",&x); //继续输入x
}
return L; //返回一个表
}
3.遍历:定义一个遍历单链表的函数:
//2.有头结点单链表的遍历
void LinkList_Printf(LinkList L){
LNode *p=L->next; //新建一个指针指向首元结点
int count=0; //定义一个计数器,计算单链表的长度
printf("单链表成员有:\n") ;
while(p!=NULL){ //循环结束条件:p的next为空时停止循环
count++; //开始计数
printf("%d ",p->data); //从首元结点开始输出
p=p->next; //移动p指针指向下一个结点
}
printf("\n");
printf("表中共有: %d 个元素\n",count) ;
}
头插法创建单链表的实现:main函数调用头插法函数List_HeadInsert、遍历函数LinkList_Printf
int main(){
LinkList L;
InitList(L);
List_HeadInsert(L);
LinkList_Printf(L);
}
后台显示:
4.尾插法--元素插在链表尾部
算法步骤:
1)从空表开始,将新结点逐个插入到链表的尾部;尾指针r指向链表的尾结点.
2)初始时r和L均指向头结点。每读入一个元素申请一个新结点,将新结点插入到尾结点之后,r指向新结点。
//4.采用尾插法创建单链表
LinkList List_TailINsert(LinkList &L){ //正向建立单链表
int x; //定义一个变量接收输入数据
L=(LNode *)malloc(sizeof(LNode)) ; //建立头节点
if(L==NULL){ //头结点的指针域包含的是首节点的地址,如果为空则内存不足,分配失败
return 0;
}
L->next=NULL; //将头结点指针域置空
LNode *s,*r=L; //s为插入元素的结点; r为尾指针 一开始先让r指向头指针
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode)); //创建新的结点s并自动分配内存空间
s->data=x; //s指针数据域赋值为x
r->next=s; //插入新结点s到尾部
r=s; //尾指针r指向新插入的结点
scanf("%d",&x);
}
r->next=NULL;//尾指针指向空
return L; //发挥一个表
}
main函数调用尾插法函数List_TailINsert--实现单链表的创建:
int main(){
LinkList L;
InitList(L);
// List_HeadInsert(L);
List_TailINsert(L) ;
LinkList_Printf(L);
// DestoryList(L);
}
后台显示:
5. 按位查找
算法步骤:
1)判断i是否合法;
2)定义一个指针p指向头结点;
3)j作为计数器,累加扫描的结点数,初值为0;
4)当j
//5.按位查找,返回第i个元素的元素值
LNode *GetElem(LinkList L,int i)
{
if(i<0){ //如过查询的i小于0 ,不合法返回空
return NULL;
}
LNode *p=L; //新建一个指针p指向头结点
int j=0; //定义一个计数器
while(p!=NULL&&jnext; //p指向下一个结点
j++; //j加1
}
return p;
}
main函数实现查询:
int main(){
LinkList L; //定义一个表
InitList(L); //初始化
// List_HeadInsert(L); //头插法调用
List_TailINsert(L) ; //尾插法调用
LinkList_Printf(L); //表的遍历
LNode *e=GetElem(L,3); //定义一个结点e赋值为返回的结点p
printf("第3个元素值为: %d\n",e->data ); //输出e结点的数据域
// DestoryList(L);
}
实现结果:
6.按值查找
//求表的长度
int Length_List(LinkList L){
int len=0;
LNode *p=L->next;
while(p!=NULL){
p=p->next;
len++;
}
return len;
}
//6-1.按值查找 ,如果查询到e并返回所在的位置i
int LocateElem_1(LinkList L,ElemType e){
int L_length=Length_List(L); //调用求表长度函数,求出表长 L_length
LNode *p=L->next;
//从第一个结点开始查询
int j=1; //定义一个计数器
while(p!=NULL&&p->data!=e){ //查询e的值是否与表中的元素相等 ,直到相等或查询结束停止循环
p=p->next;
j++;
}
if(j>L_length) { //如果表中不存在所查数据e,则返回0
return 0;
}else{
return j; //若找到e 则返回所在位置j
}
}
//6-2.按值查找 ,如果查询到e并返回所在的地址
LNode *LocateElem_2(LinkList L,ElemType e){
LNode *p=L->next;
//从第一个结点开始查询
while(p!=NULL&&p->data!=e){ //查询e的值是否与表中的元素相等 ,直到相等或查询结束停止循环
p=p->next;
}
if(p) { //当p不为空时 即查询到e对应的结点
return p; //若找到e返回结点p
}else{
return 0; //如果表中不存在所查数据e,则返回0
}
}
main函数调用函数LocateElem_1,LocateElem_2 代码如下:
int main(){
LinkList L; //定义一个表
InitList(L); //初始化
// List_HeadInsert(L); //头插法调用
List_TailINsert(L) ; //尾插法调用
LinkList_Printf(L); //表的遍历
// int i=3;
// LNode *e=GetElem(L,i); //定义一个结点e赋值为返回的结点p
// printf("第 %d 个元素值为: %d\n",i,e->data ); //输出e结点的数据域
printf("元素e=2在表中第 %d 个\n",LocateElem_1(L,2)); //输出数据e所在结点的位置
printf("元素 e=2 在表中地址为: %d\n",LocateElem_2(L,2)); //输出e的存放地址
// DestoryList(L);
}
后台显示:
1)正常查询到数据e及其地址:
2)没有查询到数据e的值:
7.插入--在第i个结点前插入值为e的新结点(或者说把值为e的结点插在第i个位置上)
算法步骤:
1)首先查询到第(i-1)个结点的存储位置p;(可以调用getElem函数查询元素)
2)生成一个数据域为e的新结点s;
3)将新结点插入到第(i-1)个结点之后;
代码为:
//7. 后插操作:p结点后插入指定结点e
bool InsertNextNode(LNode *p,ElemType e){
if(p==NULL){
return false;
}
LNode *s=(LNode *)malloc(sizeof(LNode));//定义一个新结点s,作为插入的结点
if(s==NULL){
return false;
}
s->data=e; //把e赋值给结点s的数据域
s->next=p->next; //结点s插入到p结点指向的下一个结点之前
p->next=s; //把结点s插入到p结点之后
return true;
}
//8. 按位序插入--将元素e插入表L第i个位置
bool ListInsert_L(LinkList &L,int i,ElemType e){
if(i<1){ //若i不合法,返回false
return false;
}
/*//------查询第 i-1 个结点----------------
//所以可以调用 *GetElem(LinkList L,int i) 函数进行查找
LNode *p; //定义一个p结点
int j=0; //计数当前P指针指向第几个结点
p=L; //p结点指向头结点
while(p!=NULL&&jnext;
j++;
} */
LNode *p=GetElem(L,i-1); //即可以直接调用上面的GetElem函数
/* ----将新结点插入到第(i-1)个结点之后
if(p==NULL){
return false;
}
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return true;
*/
return InsertNextNode(p,e);//后插操作: 上面注释部分操作可以封装为InsertNextNode(p,e);
}
main函数调用,代码为:
int main(){
LinkList L; //定义一个表
InitList(L); //初始化
// List_HeadInsert(L); //头插法调用
List_TailINsert(L) ; //尾插法调用
printf("插入前 \n");
LinkList_Printf(L); //表的遍历
// int i=3;
// LNode *e=GetElem(L,i); //定义一个结点e赋值为返回的结点p
// printf("第 %d 个元素值为: %d\n",i,e->data ); //输出e结点的数据域
// printf("元素e=2在表中第 %d 个\n",LocateElem_1(L,2)); //输出数据e所在结点的位置
// printf("元素 e=2 在表中地址为: %d\n",LocateElem_2(L,2)); //输出e的存放地址
ListInsert_L(L,3,666) ;//将数据域为666的结点插入表L的第3个结点位置
printf("插入后 \n");
LinkList_Printf(L); //表的遍历
// DestoryList(L);
}
显示结果:
9.删除---删除表中第i个元素并用e返回
算法步骤:
1)查询第i-1个结点;
2)删除第i个结点,并把数据域赋值给e;
3)返回e
代码:
//9.删除表L第i个位置的元素,用e返回被删除的元素的值
bool ListDelete_L(LinkList &L,int i,ElemType &e){
if(i<1){
return 0;
}
//------查询第 i-1 个结点----------------
/* LNode *p=L; //新建一个指针p指向头结点
int j=0; //定义一个计数器 计数当前P指针指向第几个结点
while(p!=NULL&&jnext; //p指向下一个结点
j++; //j加1
}*/
LNode *p=GetElem(L,i-1); //调用GetElem函数查询第i-1个结点
//如果查询到的表为空表则返回0
if(p==NULL){
return 0;
}
if(p->next==NULL){
return 0;
}
//删除第i个结点
LNode *q=p->next;//定义一个新结点指向第i个结点
p->next=q->next; //删除第i个结点
e=q->data; //把被删除的第i个结点数据域赋值给e
free(q); //清空q结点的数据
return true; //返回被删除的数据
}
10.补充操作
//-----补充 操作-------------
//1.判断单链表是否为空
int EmptyList(LinkList L){
if(L->next==NULL){
return 1;
}else{
return 0;
}
}
//2.销毁表L,销毁后不存在了
bool DestoryList(LinkList &L){
LNode *p;
while(L){
p=L;
L=L->next;
free(p);
}
return true;
}
//3.清空链表,成为空链表,头结点和头指针还存在
bool ClearList(LinkList &L){
LNode *p,*q;
p=L->next;
while(p){
q=p->next;
free(p);
p=q;
}
L->next=NULL;
return true;
}
-------------------------------------------------------全部代码-------------------------------------------------------
#include
#include
typedef int ElemType;
//定义单链表结构
typedef struct LNode{ //声明节点的类型和指向结点的指针类型
ElemType data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList; //重命名为 LNode LinkList为指向LNode的指针类型
//1.初始化,创建头结点
bool InitList(LinkList &L){
L=(LNode *) malloc(sizeof(LNode)); //定义一个新结点作为头结点,用指针L指向头结点
if(L==NULL){ //头结点的指针域包含的是首节点的地址,如果为空则内存不足,分配失败
printf("申请内存空间失败\n");
}
L->next=NULL; //给头指针的指针域置空
return true;
}
//2.有头结点单链表的遍历
void LinkList_Printf(LinkList L){
LNode *p=L->next; //新建一个指针指向首元结点
int count=0; //定义一个计数器,计算单链表的长度
printf("单链表成员有:\n") ;
while(p!=NULL){ //循环结束条件:p的next为空时停止循环
count++; //开始计数
printf(" %d ",p->data); //从首元结点开始输出
p=p->next; //移动p指针指向下一个结点
}
printf("\n");
printf("表中共有: %d 个元素\n",count) ;
}
//3.采用头插法创建单链表
//单链表建成后,顺序会与自己输入的顺序呈相反的顺序
LinkList List_HeadInsert(LinkList &L){
LNode *s; //定义一个新的结点指针
int x; //定义一个整形变量接收数据
L=(LNode *)malloc(sizeof(LNode)) ; //定义一个新结点作为头结点,用指针L指向头结点
if(L==NULL){ //头结点的指针域包含的是首节点的地址,如果为空则内存不足,分配失败
return 0;
}
L->next=NULL; //头结点的指针域设为空,即初始为空链表
scanf("%d",&x); //输入元素值
while(x!=9999){ //当输入9999结束循环
s=(LNode *)malloc(sizeof(LNode)); //创建新的结点s并自动分配内存空间
s->data=x; //把输入的值x赋值给s结点的数据域
s->next=L->next; //进行前插
L->next=s; //将头指针指向新插入的结点S
scanf("%d",&x); //继续输入x
}
return L; //返回一个表
}
//4.采用尾插法创建单链表
LinkList List_TailINsert(LinkList &L){ //正向建立单链表
int x; //定义一个变量接收输入数据
L=(LNode *)malloc(sizeof(LNode)) ; //建立头节点
if(L==NULL){ //头结点的指针域包含的是首节点的地址,如果为空则内存不足,分配失败
return 0;
}
L->next=NULL; //将头结点指针域置空
LNode *s,*r=L; //s为插入元素的结点; r为尾指针 一开始先让r指向头指针
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode)); //创建新的结点s并自动分配内存空间
s->data=x; //s指针数据域赋值为x
r->next=s; //插入新结点s到尾部
r=s; //尾指针r指向新插入的结点
scanf("%d",&x);
}
r->next=NULL;//尾指针指向空
return L; //发挥一个表
}
//5.按位查找,返回第i个元素(带头结点)的元素值
LNode *GetElem(LinkList L,int i)
{
if(i<0){ //如过查询的i小于0 ,不合法返回空
return NULL;
}
LNode *p=L; //新建一个指针p指向头结点
int j=0; //定义一个计数器
while(p!=NULL&&jnext; //p指向下一个结点
j++; //j加1
}
return p;
}
//求表的长度
int Length_List(LinkList L){
int len=0;
LNode *p=L->next;
while(p!=NULL){
p=p->next;
len++;
}
return len;
}
//------------------- 查询操作-----------------------------------------------------------------
//6-1.按值查找 ,如果查询到e并返回所在的位置i
int LocateElem_1(LinkList L,ElemType e){
int L_length=Length_List(L); //调用求表长度函数,求出表长 L_length
LNode *p=L->next;
//从第一个结点开始查询
int j=1; //定义一个计数器
while(p!=NULL&&p->data!=e){ //查询e的值是否与表中的元素相等 ,直到 相等 或 查询结束 停止循环
p=p->next;
j++;
}
if(j>L_length) { //如果表中不存在所查数据e,则返回0
return 0;
}else{
return j; //若找到e 则返回所在位置j
}
}
//6-2.按值查找 ,如果查询到e并返回所在的地址
LNode *LocateElem_2(LinkList L,ElemType e){
LNode *p=L->next;
//从第一个结点开始查询
while(p!=NULL&&p->data!=e){ //查询e的值是否与表中的元素相等 ,直到 相等 或 查询结束 停止循环
p=p->next;
}
if(p) { //当p不为空时 即查询到e对应的结点
return p; //若找到e返回结点p
}else{
return 0; //如果表中不存在所查数据e,则返回0
}
}
//--------------------------插入操作-----------------------------------------------
//7. 后插操作:p结点后插入指定结点e
bool InsertNextNode(LNode *p,ElemType e){
if(p==NULL){
return false;
}
LNode *s=(LNode *)malloc(sizeof(LNode));//定义一个新结点s,作为插入的结点
if(s==NULL){
return false;
}
s->data=e; //把e赋值给结点s的数据域
s->next=p->next; //结点s插入到p结点指向的下一个结点之前
p->next=s; //把结点s插入到p结点之后
return true;
}
//8. 按位序插入--将元素e插入表L第i个位置
bool ListInsert_L(LinkList &L,int i,ElemType e){
if(i<1){ //若i不合法,返回false
return false;
}
/*//------查询第 i-1 个结点----------------
LNode *p=L; //新建一个指针p指向头结点
int j=0; //定义一个计数器 计数当前P指针指向第几个结点
while(p!=NULL&&jnext; //p指向下一个结点
j++; //j加1
}*/
LNode *p=GetElem(L,i-1); //即可以直接调用上面的GetElem函数
/* ----将新结点插入到第(i-1)个结点之后
if(p==NULL){
return false;
}
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return true;
*/
return InsertNextNode(p,e);//后插操作: 下面的操作可以封装为InsertNextNode(p,e);
}
//----------------删除-----------------
//9.删除表L第i个位置的元素,用e返回被删除的元素的值
bool ListDelete_L(LinkList &L,int i,ElemType &e){
if(i<1){
return 0;
}
//------查询第 i-1 个结点----------------
/* LNode *p=L; //新建一个指针p指向头结点
int j=0; //定义一个计数器 计数当前P指针指向第几个结点
while(p!=NULL&&jnext; //p指向下一个结点
j++; //j加1
}*/
LNode *p=GetElem(L,i-1); //调用GetElem函数查询第i-1个结点
//如果查询到的表为空表则返回0
if(p==NULL){
return 0;
}
if(p->next==NULL){
return 0;
}
//删除第i个结点
LNode *q=p->next;//定义一个新结点指向第i个结点
p->next=q->next; //删除第i个结点
e=q->data; //把被删除的第i个结点数据域赋值给e
free(q); //清空q结点的数据
return true; //返回被删除的数据
}
//-----补充 操作-------------
//1.判断单链表是否为空
int EmptyList(LinkList L){
if(L->next==NULL){
return 1;
}else{
return 0;
}
}
//2.销毁表L,销毁后不存在了
bool DestoryList(LinkList &L){
LNode *p;
while(L){
p=L;
L=L->next;
free(p);
}
return true;
}
//3.清空链表,成为空链表,头结点和头指针还存在
bool ClearList(LinkList &L){
LNode *p,*q;
p=L->next;
while(p){
q=p->next;
free(p);
p=q;
}
L->next=NULL;
return true;
}
int main(){
LinkList L; //定义一个表
InitList(L); //初始化
// List_HeadInsert(L); //头插法调用
// List_TailINsert(L) ; //尾插法调用
printf("插入前");
LinkList_Printf(L); //表的遍历
// int i=3;
// LNode *e=GetElem(L,i); //定义一个结点e赋值为返回的结点p
// printf("第 %d 个元素值为: %d\n",i,e->data ); //输出e结点的数据域
// printf("元素e=2在表中第 %d 个\n",LocateElem_1(L,2)); //输出数据e所在结点的位置
// printf("元素 e=2 在表中地址为: %d\n",LocateElem_2(L,2)); //输出e的存放地址
ListInsert_L(L,1,666) ; //将数据域为666的结点插入表L的第3个结点位置
ListInsert_L(L,2,777) ;
printf("插入后");
LinkList_Printf(L); //表的遍历
// ElemType e;
// int i=1;
// ListDelete_L(L,i,e);
// printf("删除后");
//
// LinkList_Printf(L); //表的遍历
// printf("删除的元素为:%d\n",e);
// ClearList(L);
DestoryList(L);
}