王道单链表课后题代码实现及链表基本操作实现

链表的基本定义与方法列表

#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
typedef int Element;


typedef struct LNode{
    
    
	Element data;
	LNode *next;
}*LinkList;

bool InitList(LinkList &L);		//初始化线性表 L
bool DestoryList(LinkList &L);	//销毁单链表 L 
int Length(LinkList &L);		//求线性表 L 的长度 
void PrintList(LinkList &L);		//输入单链表 L 中的所有元素 
void PrintList(LinkList &L); 		//判断单链表 L 是否为 NULL
bool HeadInsert(LinkList &L);			//使用 头 插法向单链表 L 中插入数据
bool TailInsert(LinkList &L);			//使用 尾 插法向单链表 L 中插入数据
bool DeleteList(LinkList &L, int i);		//删除单链表 L 中的第i个元素 
bool InsertList(LinkList &L, int i, Element data);		//在单链表 L 的第i个位置插入一个新的元素 
bool PreInsert(LinkList &L, int i);			//已知链表 L 为单链表, 要求在第i个结点 前插结点s(删除同理)  
LNode *GetElem(LinkList L, int i);				//按照 序号 在单链表中查找所对应的结点 
LNode *LocateElem(LinkList L, Element e);		//按照 值 检索单链表中所对应的结点 

实现课后题的函数列表

/*-------王道课后习题-----------*/
void RecursionDeleteX(LinkList &L, Element x); 	//1.设计一个递归算法,删除不带头结点的单链表 L 中所有值为 x 的结点 
bool DeleteX(LinkList &L, Element x);			//2.删除单链表 L 中所有值为x的结点,并释放其空间 
void ReversePrint(LinkList &L);					//3.从尾至首依次输出单链表 L 的所有值
bool DeleteMinValue(LinkList &L);				//4.编写一个删除单链表 L 中最小值的高效算法
LinkList ReverseList(LinkList &L);				//5.将一个单链表 L 就地逆序存放
void SortLinkList(LinkList &L);					//6.设计一个带头结点的单链表 L , 设计一个算法使其元素递增有序
bool DeleteBetweenST(LinkList &L, Element s, Element t);		//7. 删除单链表中所有介于给定值之间的结点(同2)
LinkList GetPublicNode(LinkList &L1, LinkList &L2);				//8.给定两个单链表,编写算法找到两个结点的公共结点
bool FindMax(LinkList &L, LinkList &max, LinkList &pre_max);			//找到一个单链表中最大的结点和它的前驱结点 
bool OrderDelete(LinkList &L);							//9.按递增次序输出单链表中各结点的数据元素,并释放结点所占的存储空间
bool DevideList(LinkList &LA, LinkList &LB);			//10.链表A分为两个链表A和B,链表A存放原链表奇数部分,链表B存放原链表偶数部分 
bool DeleteOrderSameValue(LinkList &L);					//12.删除递增有序链表中的重复元素
LinkList MergeList(LinkList &L1, LinkList &L2);			//13.将两个元素值递增的单链表合并,生成一个元素值递减的新链表 
LinkList MergeSameValue(LinkList L1, LinkList L2);		//14. 设计一个算法从有序单链表A和B的公共元素产生链表C
bool isSubsequence(LinkList &LA, LinkList &LB);			//16. 判断序列B是否为序列A的连续子序列 

全部函数的具体代码(因为时间有限,没有来得及整理,比较重要的代码会有注释在里面)

/*----------------------------------------------------------------------单链表的基本函数-------------------------------------------------------*/ 

//使用头插法插入向单链表 L 中插入数据 
bool HeadInsert(LinkList &L){
    
    
	int is_insert;
	LNode *p;
	printf("插入数据(输入9999结束插入):\n");
	scanf("%d", &is_insert);
	while(is_insert != 9999){
    
    
		p = (LNode *)malloc(sizeof(LNode));
		p->data = is_insert;
		p->next = L->next;
		L->next = p;
		printf("插入成功, 请继续插入数据(输入9999结束插入):\n");
		scanf("%d", &is_insert);
	}
	return true;
}



//使用尾插法向线性表 L 中插入数据 
bool TailInsert(LinkList &L){
    
    
	int is_insert;
	LNode *p, *tail = L;
	printf("插入数据(输入9999结束插入):\n");
	scanf("%d", &is_insert);
	while(is_insert != 9999){
    
    
		p = (LNode *)malloc(sizeof(LNode));
		p->data = is_insert;
		tail->next = p;
		tail = p;
		printf("插入成功, 请继续插入数据(输入9999结束插入):\n");
		scanf("%d", &is_insert);
	}
	tail->next = NULL;
	return true;
}


//按照序号查找结点值 
LNode *GetElem(LinkList L, int i){
    
    
	int count = 0;
	LNode *p = L;
	if(i == 0) return L;
	if(i < 0) return NULL;
	while(p != NULL && count < i){
    
    
		p = p->next;
		count++;
	}
	if(p != NULL)
		return p;
	else
		return NULL;
}


//按值查找表结点
LNode *LocateElem(LinkList L, Element e){
    
    
	LNode *p = L->next;
	while(p != NULL){
    
    
		if(p->data == e)
			return p;
		p = p->next;
	}
	return NULL;
}



//插入结点操作
bool InsertList(LinkList &L, int i, Element data){
    
    
	if(i < 1 || i > Length(L)+1)
		return false;

	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = data;
	s->next = NULL;
	
	LNode *p = GetElem(L, i-1);
	s->next = p->next;
	p->next = s;
	
	return true;
}


//已知链表 L 为单链表, 要求在第i个结点 前插结点s(删除同理) 
bool PreInsert(LinkList &L, int i){
    
    
	if(i < 1 || i > Length(L))		//仅可以插入到第一个结点和最后一个结点之前 
		return false;
	int is_insert = 0, temp;
	
	printf("请输入要插入的数据:\n");		//生成要插入的数据结点 
	scanf("%d", &is_insert);
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = is_insert;
	s->next = NULL;
	
	LNode *p = GetElem(L, i);			//找到第i个位置的结点 
	s->next = p->next;					//逻辑上实现前插操作 
	p->next = s;
	temp = s->data;
	s->data = p->data;
	p->data = temp;
	
	return true;
}


//删除单链表中的第i个元素 
bool DeleteList(LinkList &L, int i){
    
    
	if(i<1 || i>Length(L))
		return false;
	
	LNode *p = GetElem(L, i-1);		//找到第i-1个元素 
	LNode *q = p->next;				//在单链表中删除第i个元素 
	p->next = q->next;
	free(q);
	
	return true;
}



//初始化线性表 L 
bool InitList(LinkList &L){
    
    
	L->data = 0;
	L->next = NULL;
	return true;
}


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


//输入单链表中的所有元素 
void PrintList(LinkList &L){
    
    
	LNode *p = L->next;
	while(p != NULL){
    
    
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}


//判断单链表是否为 NULL 
bool Empty(LinkList &L){
    
    
	if(L->next == NULL)
		return true;
	else
		return false;
}


//销毁单链表 L  
bool DestoryList(LinkList &L){
    
    
	LNode *p = NULL;
	while(L->next != NULL){
    
    
		p = L->next;
		L->next = p->next;
		free(p);
	}
	L->data = 0;
	return true;
}




/*-------------------------------------------------------------------王道课后练习习题-------------------------------------------------------------------------------*/ 

/*
1.设计一个递归算法,删除不带头结点的单链表 L 中所有值为 x 的结点 
*/
void RecursionDeleteX(LinkList &L, Element x){
    
    
	if(L == NULL)				//若 L 为空表,则直接进行返回 
		return;
	if(L->data == x){
    
    			//若 L->data 为 x, 则对其进行删除 
		LNode *p = L;		//定义指针变量 p 指向当前结点 
		/*
			非常重要!!!
			该结点指针 L 后移,指向下一结点,注意,由于 L指针为引用数据类型,
			所以L指向结点变化时,它上一层结点的next域也将指向下一结点,这样就可以避免删除操作造成的断链现象 
		*/
		L = L->next;			
		
		free(p);	//此时再将该结点删除 
		RecursionDeleteX(L, x);			//继续递归查找删除子链表中值为 x 的结点 
	}else{
    
    
		RecursionDeleteX(L->next, x);	//结点不是x的话就继续递归下层子链表 
	}
}



/*
2.删除单链表中所有值为x的结点,并释放其空间
*/
bool DeleteX(LinkList &L, Element x){
    
    
	if(L->next == NULL)
		return false;
	LNode *p = L->next, *q = L, *temp;
	while(p != NULL){
    
    
		if(p->data == x){
    
    
			temp = p;
			p = p->next;
			q->next = p;
			free(temp);
		}else{
    
    
			q = p;
			p = p->next;
		}
	}
	return true;
}


/*
3.从尾至首依次输出单链表的所有值 
*/
void ReversePrint(LinkList &L){
    
    
	if(L->next != NULL)
		ReversePrint(L->next);
	if(L != NULL && L->data != 0)
		printf("%d ", L->data);
}



/*
4.编写一个删除单链表 L 中最小值的高效算法 
(注意王道书上实现方式,更加方便,类似于打擂台算法,使用两个指针分别存放最小值结点及其前驱)
*/
bool DeleteMinValue(LinkList &L){
    
    
	if(L->next == NULL)
		return false;
	if(L->next->next == NULL){
    
    
		LNode *temp = L->next;
		L->next = temp->next;
		free(temp);
	}
	int tempi = 0;
	LNode *q = L->next, *p = L->next->next;
	while(p->next != NULL){
    
    						//边循环边比较,将最小的元素值移动至倒数第二个 
		if(q->data < p->data){
    
    
			tempi = q->data;
			q->data = p->data;
			p->data = tempi;
		}
		q = p;
		p = p->next;
	}
	if(q->data < p->data)			//将最小元素再与倒数第一元素比较大小,决定删除哪一个 
		q->data = p->data;
	q->next = p->next;
	free(p);
}

/*
5.将一个单链表 L 就地逆序存放 
*/ 
LinkList ReverseList(LinkList &L){
    
    
	if(L->next == NULL)					//若单链表为空则直接返回 
		return L;
		
	LNode *q = L, *p = L->next, *temp;		//定义q指针指向前一个元素,p指针指向后一个元素,temp为临时指针 
	q->next = NULL;						//将即将形成的链表链尾的指针域置 NULL 
	while(p != NULL){
    
    
		q->data = p->data;				//将后一个元素的值赋值给前一个元素 
		temp = p->next;				//temp暂时记录下一元素 
		p->next = q;				//p指针此时反向指向q,即q将作为p的后继指针 
		q = p;						//q指针后挪 
		p = temp;					//p指针后挪 
	}
	q->data = 0;				//将最后形成的头结点数据域清 0
	L = q;						//最终 将 q赋值给 L 作为头结点 
	return L;
}

/*
6.设计一个带头结点的单链表 L , 设计一个算法使其元素递增有序
本题算法思想,将单链表 L 从头部拆分为两个链表,第一个链表初始化仅有一个元素,
故有序,逐渐将第二个链表中的元素插入到第一个链表 L , 使其依旧有序,当全部插入完成后,该链表就实现了排序
类似于 H---->12---->2---->1----->5---->3...... 
L1 = (H---->12---->NULL)				//pre指针作为循环遍历该链表的指针, 用于确定插入位置 
L2 = (2---->1---->5---->3......)		//逐渐将L2的结点按序插入L1即可完成排序, 其中p指向该链表的表头结点, r为p后继结点 
*/
void SortLinkList(LinkList &L){
    
    
	if(L->next == NULL)
		return;
	LNode *p, *pre, *r;			//p 作为 循环遍历链表 L2, pre 作为 循环遍历 L1, r暂存p的后继结点 
	p = L->next;				//实现链表的分割 
	r = p->next;
	p->next = NULL;
	p = r;
	while(p != NULL){
    
    			//循环遍历第二个链表,将其有序插入链表1中 
		r = p->next;
		pre = L;
		while(pre->next!=NULL && pre->next->data < p->data)		//确定插入位置 
			pre = pre->next;
		p->next = pre->next;			//进行插入操作 
		pre->next = p;
		p = r;					// p 指针后移 
	}
}


/*
7. 删除单链表中所有介于给定值之间的结点(同2) 
*/
bool DeleteBetweenST(LinkList &L, Element s, Element t){
    
    
	if(L->next == NULL)
		return false;
	LNode *p = L->next, *q = L, *temp;
	while(p != NULL){
    
    
		if(p->data>=s && p->data<=t){
    
    
			temp = p;
			p = p->next;
			q->next = p;
			free(temp);
		}else{
    
    
			q = p;
			p = p->next;
		}
	}
	return true;
}


//返回单链表中最大值结点的前一个结点 
bool FindMax(LinkList &L, LinkList &max, LinkList &pre_max){
    
    
	if(L->next == NULL) return false;
	LNode *q = L, *p = L->next;
	pre_max = L, max = L->next;
	while(p != NULL){
    
    
		if(p->data > max->data){
    
    
			max = p;
			pre_max = q;
		}
		q = p;
		p = p->next;
	}
	return true;
}


/*
8.给定两个单链表,编写算法找到两个结点的公共结点 
*/
LinkList GetPublicNode(LinkList &L1, LinkList &L2){
    
    
	if(L1->next==NULL || L2->next==NULL)
		return false;
	int len1 = Length(L1), len2 = Length(L2), dist;
	LinkList short_list, long_list;
	
	if(len1 > len2){
    
    			//确定一个较长的链表和较短的链表,并得到他们的差值 
		long_list = L1->next;
		short_list = L2->next;
		dist = len1-len2;
	}else{
    
    
		long_list = L2->next;
		short_list = L1->next;
		dist = len2-len1;
	}
	
	for(int i=1; i<=dist; i++){
    
    			//根据差值,长链表指针依次后移,目的实现长短链表同步开始寻找公共结点 
		long_list = long_list->next;
	}
	
	while(long_list != NULL){
    
    				//循环遍历寻找公共结点 
		if(short_list->data == long_list->data)
			return long_list;
		short_list = short_list->next;
		long_list = long_list->next;
	}
	return NULL;
}


/*
9.按递增次序输出单链表中各结点的数据元素,并释放结点所占的存储空间 
*/
bool OrderDelete(LinkList &L){
    
    
	LNode *p, *pre_max, *temp;
	while(L->next != NULL){
    
    			//单链表不为NULL,则一直循环查找最小值并删除 
		
		pre_max = L;					//pre_max始终指向当前最小值元素的前驱结点 
		p = L->next;					//作为工作指针 
		
		//查找出单链表的最小值结点,pre_max将指向其前驱结点 
		while(p->next != NULL){
    
    
			if(p->next->data < pre_max->next->data)		//循环遍历比较 
				pre_max = p;						//记住当前最小值结点的前驱结点 
			p = p->next;
		}
		
		printf("正在删除数据---->\t%d.\n", pre_max->next->data);		//输出结点 
		
		temp = pre_max->next;					//删除结点 
		pre_max->next = temp->next;
		free(temp);
		
	}
}


/*
10.链表A分为两个链表A和B,链表A存放原链表奇数部分,链表B存放原链表偶数部分 
*/ 
bool DevideList(LinkList &LA, LinkList &LB){
    
    
	if(LA->next == NULL)
		return false;
	InitList(LB);
	int count = 0;
	LNode *p1 = LA, *p2 = LB, *temp;
	while(p1->next != NULL){
    
    
		if((++count)%2 == 0){
    
    
			temp = p1->next->next;
			
			p1->next->next = NULL;
			p2->next = p1->next;
			p2 = p1->next;
//			p1->next->next = LB->next;		//第11题答案只需将上三行换为该两行即可,是为头插法 
//			LB->next = p1->next;			
			
			
			
			p1->next = temp;
			
		}else
			p1 = p1->next;
	}
	return true;
}



/*
12.删除递增有序链表中的重复元素 
*/
bool DeleteOrderSameValue(LinkList &L){
    
    
	if(L->next == NULL)
		return false;
	LNode *q = L->next, *p = L->next->next, *temp;
	while(p != NULL){
    
    
		if(q->data != p->data){
    
    
			q = p;
			p = p->next;
		}else{
    
    
			temp = p->next;
			q->next = temp->next;;
			free(temp);
		}
	}
	return true;
}



/*
13.将两个元素值递增的单链表合并,生成一个元素值递减的新链表 
*/
LinkList MergeList(LinkList &L1, LinkList &L2){
    
    
	if(L1->next == NULL || L2->next == NULL)
		return NULL;
	LNode *p1 = L1, *p2 = L2, *temp;
	while(p1->next != NULL && p2->next != NULL){
    
    
		if(p1->next->data > p2->next->data){
    
     		//若p1所指结点的值大于 p2所指结点的值 
			temp = p2->next->next;
			
			p2->next->next = p1->next;			//将 p2所指结点 连接到 p1所指结点之前  
			p1->next = p2->next;
			
			p2->next = temp;					// p2 指针后移 
		}else
			p1 = p1->next;			//否则 p1 指针后移 
	}
	while(p2->next != NULL){
    
    			//将剩余结点全部连接到 p1 之上 
		p1->next = p2->next;
		p2 = p2->next;	
	}
	L1 = ReverseList(L1);				//将最后所得结果再逆序存放一下即可 
	return L1;
}


/*
14. 设计一个算法从有序单链表A和B的公共元素产生链表C 
*/
LinkList MergeSameValue(LinkList L1, LinkList L2){
    
    
	LinkList L = (LNode *)malloc(sizeof(LNode));
	InitList(L);
	LNode *p1 = L1->next, *p2 = L2->next;
	while(p1!=NULL && p2!=NULL){
    
    
		if(p1->data == p2->data){
    
    
			InsertList(L, Length(L)+1, p1->data);
			p1 = p1->next;
			p2 = p2->next;
		}else if(p1->data < p2->data){
    
    
			p1 = p1->next;
		}else{
    
    
			p2 = p2->next;
		}
	}
	return L;
}



/*
16. 判断序列B是否为序列A的连续子序列 
*/
bool isSubsequence(LinkList &LA, LinkList &LB){
    
    
	if(LB->next == NULL)
		return true;
	LNode *p1 = LA->next, *p2 = LB->next;
	while(p1 != NULL){
    
    
		LNode *k1 = p1, *k2 = p2;
		while(k1!=NULL && k2!=NULL){
    
    
			if(k1->data != k2->data) break;
			k1 = k1->next;
			k2 = k2->next;
		}
		if(k2 == NULL)
			return true;
		p1 = p1->next;
	}
	return false;
}

猜你喜欢

转载自blog.csdn.net/weixin_43479947/article/details/117641035