线性表的链式表示--王道2024DS习题代码

2024年王道数据结构考研复习指导第二章:线性表的链式表示——课后综合应用题个人学习的相关运行代码。

#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{		//定义单链表结点类型 
	int data;				//数据域 
	struct LNode *next;		//指针域 
}LNode, *LinkList;

//初始化一个单链表(带头结点)
bool InitHList(LinkList &L){
	//分配一个头结点 
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL)				//内存不足,分配失败 
		return false;
	L->next=NULL;			//头结点之后暂时还没有结点
	/*
	初始化循环单链表 
	L->next=L; 
	*/
	return true;
} 

//初始化一个单链表(不带头结点)
bool InitList(LinkList &L){
	L=NULL;					//空表,无任何结点 
	return true;
}

//判断单链表是否为空
bool Empty(LinkList L){
	if(L->next==NULL)		/*如果NULL改为L,则是为判断循环单链表*/
		return true;
	else
		return false;
} 

//判断结点p是否表尾结点 
bool isTail(LinkList L, LNode *p){
	if(p->next==NULL)		/*如果NULL改为L,则是为判断循环单链表*/ 
		return true;
	else
		return false;
}

//尾插法建立单链表(带头结点) 
LinkList List_HTailInsert(LinkList &L){
	int x;
	L=(LinkList)malloc(sizeof(LNode));
	LNode *s, *r=L;			//r为表尾指针 
	scanf("%d", &x);		//输入结点的值 
	while(x!=9999){			//输入9999表示结束 
		s=(LNode*)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;				//r指向新的表尾结点 
		scanf("%d", &x);
	}
	r->next=NULL;			//尾结点指针置空 
	return L;
} 

//尾插法建立单链表(不带头结点) 
LinkList List_TailInsert(LinkList &L){
	int x;
	InitList(L);
	LNode *s, *r;			//r为表尾指针 
	scanf("%d", &x);		//输入结点的值 
	while(x!=9999){			//输入9999表示结束 
		s=(LNode*)malloc(sizeof(LNode));
		s->data=x;
		s->next=NULL;		//尾结点指针置空 
		if(L==NULL){		//链表是否为空 
			L=s;
			r=L;
		}
		else{
			r->next=s;
			r=s;
		}
		scanf("%d", &x);
	}
	return L;
} 

//头插法建立单链表!链表的逆置 
LinkList List_HeadInsert(LinkList &L){
	LNode *s;
	int x;
	L=(LinkList)malloc(sizeof(LNode));
	L->next=NULL;			//初始为空链表 
	scanf("%d", &x);		//输入结点的值
	while(x!=9999){			//输入9999表示结束
		s=(LNode*)malloc(sizeof(LNode));
		s->data=x;
		s->next=L->next;
		L->next=s;				//将新结点插入表中,L为头指针 
		scanf("%d", &x);
	} 
	return L;
} 

//打印单链表(不带头结点) 
void PrintLinkList(LinkList &L){
	LNode *p=L;
	if(p==NULL){
		printf("\n\t链表为空。\n");
	}
	else{
		printf("\n\t链表内容为:");
    	while(p){
        	printf("%d ", p->data);
        	p=p->next;
    	}
	}
    printf("\n");
}

//打印单链表(带头结点) 
void PrintHLinkList(LinkList &L){
	LNode *p=L;
	if(p->next==NULL){
		printf("\n\t链表为空!\n");
	}
	else{
		printf("\n\t链表内容为:");
    	while(p->next!=NULL){
        	printf("%d ", p->next->data);
        	p=p->next;
    	}
	}
    printf("\n");
}

//按序号查找结点
LNode *GetElem(LinkList L, int i){
	if(i<0)
		return NULL;
	/* 需添加代码(不带头结点) 
	if(i==1){				//插入第1个结点的操作与其它结点操作不同 
		LNode *s=(LNode*)malloc(sizeof(LNode));
		if(s==NULL)				//内存分配失败 
			return false;
		s->data=e;
		s->next=L;
		L=s;				//头指针指向新结点 
		return true;
	} 
	*/
	LNode *p;				//指针p指向当前扫描到的结点 
	int j=0;				//当前p指向的是第几个结点(若不带头结点则j=1) 
	p=L;					//L指向头结点,头结点是第0个结点(不存数据) 
	while(p!=NULL&&j<i){	//循环找到第i个结点 
		p=p->next;
		j++;
	}
	return p;
} 

//按值查找,找到数据域==e的结点
LNode *LocateElem(LinkList L, int e){
	LNode *p=L->next;
	//从第1个结点开始查找数据域为e的结点
	while(p!=NULL&&p->data!=e)
		p=p->next;
	return p;				//找到后返回该结点指针,否则返回NULL 
} 

//求表的长度
int Length(LinkList L){
	int len=0;				//统计表长 
	LNode *p=L->next;
	while(p!=NULL){
		p=p->next;
		len++;
	}
	return len;
} 

//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p, int e){
	if(p==NULL)				 
		return false;
	LNode *s=(LNode*)malloc(sizeof(LNode));
	if(s==NULL)				//内存分配失败 
		return false;
	s->data=e;				//用结点s保存数据元素e 
	s->next=p->next;		
	p->next=s;				//将结点s连接到p之后 
	return true;			
} 

//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p, int e){
	if(p==NULL)
		return false;
	LNode *s=(LNode*)malloc(sizeof(LNode));
	if(s==NULL)				//内存分配失败 
		return false; 
	s->next=p->next;		
	p->next=s;				//将新结点s连接到p之后 
	s->data=p->data;		//将p中元素复制到s中 
	p->data=e;				//p中元素覆盖为e,成功前插 
	return true;
} 

//在第i个位置插入元素e(带头结点) 
bool ListInsert(LinkList &L, int i, int e){
	if(i<1)
		return false; 
	LNode *p;
	p=GetElem(L, i-1);
	return InsertNextNode(p, e);
} 

//删除指定结点p
bool DeleteNode(LNode *p){
	if(p==NULL)
		return false;
	LNode *q=p->next;
	p->data=p->next->data;
	p->next=q->next;
	free(q);
	return true;
} 

//按位序删除(带头结点)
bool ListDelete(LinkList &L, int i, int &e){
	if(i<1)
		return false;
	LNode *p;
	p=GetElem(L, i-1);
	if(p==NULL)				//i值不合法 
		return false;
	if(p->next==NULL)		//第i-1个结点之后已无其他结点 
		return false;
	LNode *q=p->next;		//令q指向被删除的结点 
	e=q->data;				//用e返回元素的值 
	p->next=q->next;		//将*q结点从链中“断开” 
	free(q);				//释放结点的存储空间 
	return true;			//删除成功 
} 

//递归删除带头H中所有x值 
void Del_HX(LinkList &H, int num){
	LNode *p=H->next; 			//从链表的第一个节点开始查找
	LNode *prev=H; 				//用于记录前一个节点
	while(p!=NULL){
		if(p->data==num){
			LNode *temp=p; 		//用于暂存要删除的节点
			prev->next=p->next; //将前一个节点的next指针指向当前节点的下一个节点
			p=p->next; 			//将p指针移动到下一个节点
			free(temp); 		//释放暂存的节点内存
		}
		else{
			prev=p; 			//更新前一个节点指针
			p=p->next;			//移动到下一个节点
		}
	}
}

//递归删除不带头结点的单链表L中所有x值
void Del_X(LinkList &L, int x){
	LNode *p;				//p指向待删除结点 
	if(L==NULL)				//递归出口 
		return;
	if(L->data==x){			//若L所指结点的值为x 
		p=L;				//删除*L,并让L指向下一结点 
		L=L->next;
		free(p);
		Del_X(L, x);		//递归调用 
	}
	else					//若L所指结点的值不为x 
		Del_X(L->next, x);	//递归调用 
} 

//递归删除带头结点的单链表L中所有a-b之间值
void Del_HX_ab(LinkList &H, int a, int b){
	LNode *p;				//p指向待删除结点 
	if(H->next==NULL)		//递归出口 
		return;
	//若L所指结点的值为x
	if(H->next->data>=a&&H->next->data<=b){	 
		p=H->next;			//删除*H,并让H指向下一结点 
		H->next=H->next->next;
		free(p);
		Del_HX_ab(H, a, b);	//递归调用 
	}
	else					//若L所指结点的值不为x 
		Del_HX_ab(H->next, a, b); 
} 

//逐点检查带头H中a-b之间的值并删除 
void RangeDelete(LinkList &H, int a, int b){
	LNode *pr=H, *p=H->next;
	while(p!=NULL){
		if(p->data>=a&&p->data<=b){
			pr->next=p->next;
			free(p);
			p=pr->next;
		}
		else{
			pr=p;
			p=p->next;
		}
	}
}

//摘下头结点依次头插法实现逆置 
LinkList Reverse_1(LinkList &H){
	LNode *p, *r;			//p为工作指针,r为p的后继以防断链 
	p=H->next;				//从第一个元素结点开始 
	H->next=NULL;			//先将头结点L的next域置为NULL 
    while(p!=NULL){			//依次将元素结点摘下 
		r=p->next;			//暂存p的后继 
		p->next=H->next; 	//将p结点插入到头结点之后 
		H->next=p;
		p=r;
	} 
	return H;
} 

//在带头单链表H中删除最小值并打印表 
LinkList Delete_Min(LinkList &H){
	if(!Empty(H)){
		LNode *pre=H;
		LNode *p=pre->next;		//p为工作指针,pre指向其前驱
		LNode *minpre=pre;
		LNode *minp=p;			//保存最小值结点及其前驱 
		while(p!=NULL){
			if(p->data<minp->data){
				minp=p;
				minpre=pre;
			} 
			pre=p;				//继续扫描下一个结点 
			p=p->next;
		} 
		minpre->next=minp->next;//删除最小值结点
		free(minp);
		PrintHLinkList(H);
	}
	else{
		printf("\n\t链表为空,无法删除!\n");
	}
} 

//空间复杂O(1)的单链表就地逆置
LinkList Reverse_2(LinkList &H){
	//只使用额外的指针变量pre,p,r来完成逆置,即常数级空间复杂O(1) 
	LNode *pre, *p=H->next, *r=p->next;
	p->next=NULL;			//处理出最后结点 
	while(r!=NULL){			//直到r空,说明p为原表最后一个结点 
		pre=p;
		p=r;
		r=r->next;
		p->next=pre;		//指针反转 
	}
	H->next=p;
	return H;
} 

//递增排序带头H表
void SortAscend(LinkList &H){
	LNode *p=H->next, *pre;	
	LNode *r=p->next;		//r保持*p后继结点指针保证不断链 
	p->next=NULL;			//构造只含一个数据结点的有序表 
	p=r;
	while(p!=NULL){
		r=p->next;			//保存*p的后继结点指针 
		pre=H;
		while(pre->next!=NULL&&pre->next->data<p->data)
			pre=pre->next;	//在有序表中查找插入*p的前驱结点*pre 
		p->next=pre->next;	//把*p插入到pre之后 
		pre->next=p;
		p=r;				//继续扫描原表剩余结点 
	}
}

//给定两个链表并输出公共结点 
LinkList List_Same(LinkList &A, LinkList &B, LinkList &C){
	LNode *p=A->next;
	LNode *q=B->next;
	LNode *s, *r=C;			//r为表尾指针
	while(p!=NULL&&q!=NULL){
		if(p->data==q->data){
			s=(LNode*)malloc(sizeof(LNode));
			s->data=p->data;
			r->next=s;
			r=s; 			//r指向新的表尾结点 
			p=p->next;
			q=q->next; 		//移动q指针
		}
		else if(p->data<q->data){
			p=p->next;
		}
		else{
			q=q->next;
		}
	}
	r->next=NULL; 			//尾结点指针置空
	return C;
}

//给定两个单链表找第一个公共结点 
LinkList Search_1st_Common(LinkList &H1, LinkList &H2){
	int dist;
	int len1=Length(H1), len2=Length(H2);
	LinkList longList, shortList;
	if(len1>len2){
		longList=H1->next;
		shortList=H2->next;
		dist=len1-len2;
	}
	else{
		longList=H2->next;
		shortList=H1->next;
		dist=len2-len1;
	}
	while(dist--)
		longList=longList->next;
	while(longList!=NULL){
		if(longList==shortList)
			return longList;
		else{
			longList=longList->next;
			shortList=shortList->next;
		}
	}
	return NULL;
}

//去重递增带头H
void Del_Same(LinkList &H){
	LNode *p=H->next, *q;
	if(p==NULL)
		return;
	while(p->next!=NULL){
		q=p->next;
		if(p->data==q->data){
			p->next=q->next;
			free(q);
		}
		else
			p=p->next;
	}
}

int main(){
	LinkList L;				//声明一个单链表 (不带头结点) 
	InitList(L);			//初始化单链表(不带头结点) 
	LinkList H, A, B;		//声明三个单链表 (带头结点) 
	InitHList(H);			//初始化单链表(带头结点)
	InitHList(A);
	InitHList(B);
	int i=1, choice;
	int num, a, b;
	while(i)
	{
		printf("\n\t****************单  链  表*****************"); 
		printf("\n\t*                                         *");
		printf("\n\t*       0--创建一个不带头单链表L          *"); 
		printf("\n\t*       1--创建一个带头单链表H            *"); 
		printf("\n\t*       2--递归删除不带头L中所有x值       *");
		printf("\n\t*       3--删除带头H中所有x值             *");
		printf("\n\t*       4--反向输出带头H的各结点值        *");
		printf("\n\t*       5--在带头H中删除最小值并打印表    *");
		printf("\n\t*       6--就地逆置带头H的结点            *");
		printf("\n\t*       7--递增排序带头H表                *");
		printf("\n\t*       8--删除带头H中a-b之间的值         *");
		printf("\n\t*       9--给定两个链表并输出公共结点     *");
		printf("\n\t*      10--递增输出带头H各结点并free      *");
		printf("\n\t*      11--分解带头A为奇序A和偶序B表      *");
		printf("\n\t*      12--去重递增带头H                  *");
		printf("\n\t*      -1--   返     回                   *");  
		printf("\n\t*                                         *");
		printf("\n\t*******************************************"); 
		printf("\n\t请选择菜单号(0--10):"); 
		scanf("%d",&choice);
		switch(choice)
		{
			case 0:
			{
				printf("\n\t请开始建立不带头单链表并输入9999结束:");
				List_TailInsert(L);
				PrintLinkList(L);
				break; 
			}
			case 1:
			{
				printf("\n\t请开始建立带头单链表并输入9999结束:");
				List_HTailInsert(H);
				PrintHLinkList(H);
				break;
			}
			case 2:
			{
				printf("\n\t请输入需要输出的x的值:");
				scanf("%d", &num);
				Del_X(L, num);
				printf("\n\t成功删除不带头L中所有x值!\n");
				PrintLinkList(L);
				break;
			}	
			case 3:
			{
				printf("\n\t请输入需要删除的x的值:");
    			scanf("%d", &num);
    			Del_HX(H, num);
    			printf("\n\t成功删除带头H中所有x值!\n");
    			PrintHLinkList(H);
				break;
			}
			case 4:
			{
				Reverse_1(H); 				//空间复杂O(1) 
				if(!Empty(H)){
					printf("\n\t成功反向输出各结点!\n");
					PrintHLinkList(H);
				}
				else{
					printf("\n\t链表为空,无法反向输出!\n");
				}
				break;
			}
			case 5:
			{
				Delete_Min(H);
				break; 
			}
			case 6:
			{
				Reverse_2(H); 				//空间复杂O(1) 
				if(!Empty(H)){
					printf("\n\t成功就地逆置该链表各结点!\n");
					PrintHLinkList(H);
				}
				else{
					printf("\n\t链表为空,无法反向输出!\n");
				}
				break;	
			}
		    case 7:
			{
				SortAscend(H);
				printf("\n\t成功递增排序带头单链表H!\n"); 
				PrintHLinkList(H);
				break;
			} 
			case 8:
			{
				printf("\n\t请输入需要删除的值的范围a-b:");
				scanf("%d %d", &a, &b);
				//递归删除:Del_HX_ab(H, a, b); 
				RangeDelete(H, a, b);
				printf("\n\t成功删除a-b之间的结点!\n"); 
				PrintHLinkList(H);
				break;
			}
			case 9:
			{
				printf("\n\t请开始建立带头单链表A并输入9999结束:");
				List_HTailInsert(A);
				PrintHLinkList(A);
				printf("\n\t请开始建立带头单链表B并输入9999结束:");
				List_HTailInsert(B);
				PrintHLinkList(B);
				List_Same(A, B, H);
				printf("\n\t表A和表B的共同结点如下已找到!");
				PrintHLinkList(H);
				//Search_1st_Common(A, B)
				break;
			}
			case 10:
			{
				SortAscend(H);
				PrintHLinkList(H);
				num=Length(H);
				printf("\n\t递增输出带头H中各结点数据:");
				for(i=1; i<=num; i++){
					if(ListDelete(H, 1, a)){
						printf("%d ", a);
					}
				}
				free(H->next);
				printf("\n\n\t带头H存储空间释放完毕");
				PrintHLinkList(H);
				break;
			}
			case 11:
			{
				printf("\n\t原表A的内容如下");
				PrintHLinkList(H);
				LNode *s, *r=B;
				num=Length(H);
				for(i=2; i<=num; i++){
					if(ListDelete(H, i, a)){
						s=(LNode*)malloc(sizeof(LNode));
						s->data=a;
						r->next=s;
						r=s;
					}
				}
				r->next=NULL;
				printf("\n\t原表A序号为奇数的链表保留在A表");
				PrintHLinkList(H);
				printf("\n\t原表A序号为偶数的链表保留在B表");
				PrintHLinkList(B);
				break;
			}
			case 12:
			{
				Del_Same(H);
				printf("\n\t成功去重带头H");
				PrintHLinkList(H);
				break;
			} 
			case -1:
				i=0;
		    	break;
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林北发量惊人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值