数据结构-(有头结点)单链表的基本操作实现----------随笔记录(2)

(一)含有头结点单链表的基本操作的实现:(初始化、增、删、改、查,等)
单链表的结构定义:
#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);
}
后台显示:
数据结构-(有头结点)单链表的基本操作实现----------随笔记录(2)_第1张图片

 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);
}

后台显示:

数据结构-(有头结点)单链表的基本操作实现----------随笔记录(2)_第2张图片 

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);
}

实现结果:

数据结构-(有头结点)单链表的基本操作实现----------随笔记录(2)_第3张图片

 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)_第4张图片

2)没有查询到数据e的值:

数据结构-(有头结点)单链表的基本操作实现----------随笔记录(2)_第5张图片

 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);
}

显示结果:

数据结构-(有头结点)单链表的基本操作实现----------随笔记录(2)_第6张图片

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);

	

}

你可能感兴趣的:(数据结构,链表)