《数据结构(C语言版)第二版》第二章-线性表(算法设计习题)

习题一

将两个递增的有序链表合并为一个递增的有序链表。要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中不允许有重复的数据。

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};

struct Node* CreateNodeByTail(struct Node* headNode);
void printNode(struct Node* headNode);
void mergeNode(struct Node* headNodeA, struct Node* headNodeB);

int main()
{
	struct Node* listA = NULL;
	struct Node* listB = NULL;

	struct Node* list1 = CreateNodeByTail(listA);
	printNode(list1);

	struct Node* list2 = CreateNodeByTail(listB);
	printNode(list2);

	fflush(stdout);  //刷新输出缓冲区
	printf("\n");
	mergeNode(list1, list2);
	printNode(list1);

	return 0;
}

//后插法创建一个递增的单链表
struct Node* CreateNodeByTail(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;

	struct Node* s; //申请的新结点

	int numLength = 0;
	printf("请输入单链表的长度:");
	scanf_s("%d", &numLength);

	int i = 0;
	int num = 0;
	struct Node* pre = headNode;
	struct Node* p = headNode->next;

	for (i = 0; i < numLength; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);

		//遍历已存入的数值
		pre = headNode;
		p = headNode->next;
		while (p && p->data < num)
		{
			pre = p;
			p = p->next;
		}

		if (p && p->data == num)
		{
			printf("已存在该数值,请重新输入。\n");
			i--;   
			continue;   
			//中止本次for循环。
			//跳过本次for循环体中剩下尚未执行的语句,立即进行下一次的for循环
			//continue、break都只对一层循环起作用,用在内层循环时,只对内层循环其作用,对外层循环无影响。
		}

		s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;

		//找到第一个比num大的数p->data,将新结点s插入到p前面
		if (p && p->data > s->data)
		{
			s->next = p;
			pre->next = s;
		}

		if (!p)  //s->data是最大的
		{
			pre->next = s;
			s->next = NULL;
		}
	}

	return headNode;
}

//打印单链表
void printNode(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 0;

	for (i = 1; pMove != NULL; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}

	printf("\nlist_length: %d\n", i);
}


//合并单链表
void mergeNode(struct Node* headNodeA, struct Node* headNodeB)
{
	struct Node* p1 = headNodeA->next;
	struct Node* p2 = headNodeB->next;  
	//因为在下面的while循环中直接比较data值,因此p1、p2必须初始化为首元结点
	//否则无法输出!!!

	struct Node* p3 = headNodeA;

	struct Node* r = p2; //工具指针

	while (p1 && p2)
	{
		if (p1->data < p2->data)
		{
			p3->next = p1;
			p3 = p1;
			p1 = p1->next;
		}
		else if (p1->data > p2->data)
		{
			p3->next = p2;
			p3 = p2;
			p2 = p2->next;
		}
		else
		{
			p3->next = p1;
			p3 = p1;
			p1 = p1->next;

			r = p2;
			p2 = p2->next;
			free(r);
		}
	}

	if (p1)
	{
		p3->next = p1;
		p3 = p1;
		p1 = p1->next;
	}
	else
	{
		p3->next = p2;
		p3 = p2;
		p2 = p2->next;
	}
	//此处为了保证将两个链表都循环完,最好用while(p1)、while(p2)
	//但是经用长度相差较大的两个链表验证,用if也是可以的。

	free(headNodeB);
}

在这里插入图片描述

习题二

将两个非递减的有序链表合并为一个非递增的有序链表。要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中允许有重复的数据。

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};

struct Node* CreateNodeByTail(struct Node* headNode);
void printNode(struct Node* headNode);
void mergeNode(struct Node* headNodeA, struct Node* headNodeB);

int main()
{
	struct Node* listA = NULL;
	struct Node* listB = NULL;

	struct Node* list1 = CreateNodeByTail(listA);
	printNode(list1);

	struct Node* list2 = CreateNodeByTail(listB);
	printNode(list2);

	fflush(stdout);  //刷新输出缓冲区
	printf("\n");
	mergeNode(list1, list2);
	printNode(list1);

	return 0;
}

//后插法创建一个非递减的有序单链表
struct Node* CreateNodeByTail(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;

	struct Node* s; //申请的新结点

	int numLength = 0;
	printf("请输入单链表的长度:");
	scanf_s("%d", &numLength);

	int i = 0;
	int num = 0;
	struct Node* pre = headNode;
	struct Node* p = headNode->next;

	for (i = 0; i < numLength; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);

		//遍历已存入的数值
		pre = headNode;
		p = headNode->next;
		while (p && p->data < num)
		{
			pre = p;
			p = p->next;
		}

		s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;

		//找到第一个比num大的数p->data(相等也是),将新结点s插入到p前面
		s->next = p;
		pre->next = s;

		if (!p)  //s->data是最大的
		{
			pre->next = s;
			s->next = NULL;
		}
	}

	return headNode;
}

//打印单链表
void printNode(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 0;

	for (i = 1; pMove != NULL; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}

	printf("\nlist_length: %d\n", i);
}

//合并单链表
void mergeNode(struct Node* headNodeA, struct Node* headNodeB)
{
	struct Node* p1 = headNodeA->next;
	struct Node* p2 = headNodeB->next;  
	//因为在下面的while循环中直接比较data值,因此p1、p2必须初始化为首元结点
	//否则无法输出!!!

	struct Node* p3 = headNodeA;

	struct Node* r = p2; //工具指针

	while (p1 && p2)
	{
		if (p1->data <= p2->data)
		{
			p3->next = p1;
			p3 = p1;
			p1 = p1->next;
		}
		else
		{
			p3->next = p2;
			p3 = p2;
			p2 = p2->next;
		}
	}

	if (p1)
	{
		p3->next = p1;
		p3 = p1;
		p1 = p1->next;
	}
	else
	{
		p3->next = p2;
		p3 = p2;
		p2 = p2->next;
	}	
	//此处为了保证将两个链表都循环完,最好用while(p1)、while(p2)
	//但是经用长度相差较大的两个链表验证,用if也是可以的。

	free(headNodeB);
}

在这里插入图片描述

***习题三

已知两个链表A和B分别表示两个集合,其元素递增排列。请设计一个算法,用于求出A与B的交集,并存放在A链表中。

Julo白熊

思路:
求交集就是求两条链具有的相同元素的结点,A和B链结点一一比较,相同的A保留,B删除结点,不相同结点,由于是递增链,小的元素已经没有再比较的必要了,删去,当其中一条链走到结尾时,比较就结束了,只需把没有走到尾的链剩余结点清除即可。

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};

struct Node* CreateNodeByTail(struct Node* headNode);
void printNode(struct Node* headNode);
void intersectionNode(struct Node* headNodeA, struct Node* headNodeB);

int main()
{
	struct Node* listA = NULL;
	struct Node* listB = NULL;

	struct Node* list1 = CreateNodeByTail(listA);
	printNode(list1);

	struct Node* list2 = CreateNodeByTail(listB);
	printNode(list2);

	printf("\n");
	intersectionNode(list1, list2);
	printNode(list1);

	return 0;
}

//后插法创建一个递增的单链表
struct Node* CreateNodeByTail(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;

	struct Node* s; //申请的新结点

	int numLength = 0;
	printf("请输入单链表的长度:");
	scanf_s("%d", &numLength);

	int i = 0;
	int num = 0;
	struct Node* pre = headNode;
	struct Node* p = headNode->next;


	for (i = 0; i < numLength; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);

		//遍历已存入的数值
		pre = headNode;
		p = headNode->next;
		while (p && p->data < num)
		{
			pre = p;
			p = p->next;
		}

		if (p && p->data == num)
		{
			printf("已存在该数值,请重新输入。\n");
			i--;
			continue;
		}

		s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;

		//找到第一个比num大的数p->data,将新结点s插入到p前面
		if (p && p->data > s->data)
		{
			s->next = p;
			pre->next = s;
		}

		if (!p)  //s->data是最大的
		{
			pre->next = s;
			s->next = NULL;
		}
	}

	return headNode;
}

//打印单链表
void printNode(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 0;

	for (i = 1; pMove != NULL; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}

	printf("\nlist_length: %d\n", i);
}

//求两个链表的交集
void intersectionNode(struct Node* L1, struct Node* L2)
{
	//都是带头结点的链表,L1为A链,L2为B链
	struct Node* q;
	struct Node* p1 = L1->next;
	struct Node* p2 = L2->next;

	struct Node* L3 = L1;//使用第一条链的头结点
	struct Node* p3 = L3;

	while (p1 && p2)//只要一条链到尾就跳出
	{
		if (p1->data == p2->data)//相等保留
		{
			p3->next = p1;
			p3 = p1;
			p1 = p1->next;
			q = p2;//第二条链删除一个节点
			p2 = p2->next;
			delete q;
		}
	/* headNodeA中与headNodeB只要相等的,就一定是交集中的元素,不管大小。
	不管哪条链,小的元素对应节点删掉。
	因为两个链表都是递增的,因此此处小的元素一定比对面链表中后面的任意一个结点都小,所以删掉。
	较大的元素,对面链表中可能还会有与其相等的,所以不删。*/
		else if (p1->data < p2->data)
		{
			q = p1;
			p1 = p1->next;
			delete q;
		}
		else
		{
			q = p2;
			p2 = p2->next;
			delete q;
		}
	}
	
	//把剩余的节点清空
	while (p1)
	{
		q = p1;
		p1 = p1->next;
		delete q;
	}
	
	while (p2)
	{
		q = p2;
		p2 = p2->next;
		delete q;
	}
    
    free(L2);
	
	p3->next = NULL;//把新链尾巴置NULL,一定要有,不然在其他操作中报错
}

在这里插入图片描述

只会进行下图中非灰色部分的比较,红色为交集。

在这里插入图片描述

***习题四

已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出两个集合A和B的差集(即仅由在A中出现而不在B中出现的元素所构成的集合),并以同样的形式存储,同时返回该集合的元素个数。

Blakie

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};

struct Node* CreateNodeByTail(struct Node* headNode);
void printNode(struct Node* headNode);
int differenceList(struct Node* headNodeA, struct Node* headNodeB);

int main()
{
	struct Node* listA = NULL;
	struct Node* listB = NULL;
	int num = 0;

	struct Node* list1 = CreateNodeByTail(listA);
	printNode(list1);

	struct Node* list2 = CreateNodeByTail(listB);
	printNode(list2);

	printf("\n");
	num = differenceList(list1, list2);
	printNode(list1);
	printf("\n差集链表中元素的个数为:%d\n",num);

	return 0;
}

//后插法创建一个递增的单链表
struct Node* CreateNodeByTail(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;

	struct Node* s; //申请的新结点

	int numLength = 0;
	printf("请输入单链表的长度:");
	scanf_s("%d", &numLength);

	int i = 0;
	int num = 0;
	struct Node* pre = headNode;
	struct Node* p = headNode->next;


	for (i = 0; i < numLength; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);

		//遍历已存入的数值
		pre = headNode;
		p = headNode->next;
		while (p && p->data < num)
		{
			pre = p;
			p = p->next;
		}

		if (p && p->data == num)
		{
			printf("已存在该数值,请重新输入。\n");
			i--;
			continue;
		}

		s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;

		//找到第一个比num大的数p->data,将新结点s插入到p前面
		if (p && p->data > s->data)
		{
			s->next = p;
			pre->next = s;
		}

		if (!p)  //s->data是最大的
		{
			pre->next = s;
			s->next = NULL;
		}
	}

	return headNode;
}

//打印单链表
void printNode(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 0;

	for (i = 1; pMove != NULL; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}

	printf("\nlist_length: %d\n", i);
}


//差集
int differenceList(struct Node* headNodeA, struct Node* headNodeB)
{
	struct Node* pa = headNodeA->next;
	struct Node* pb = headNodeB->next;

	struct Node* headNodeC = headNodeA;
	struct Node* pc = headNodeC;
	
	int count = 0;

/* headNodeA中与headNodeB不相等的,不管大小,都一定是差集元素。
只不过由于是递增序列,pa->data小的,可以不用再与headNodeB后面的元素比较;
而pa->data大的,要确认一下headNodeB后面没有与此pa—>data相等的了。 */

/* 在headNodeA 和 headNodeB中,比出比较小的那个,且对应单链表的指针往后移。
若pa->data比较小,则此pa->data一定是差集中的元素,将其添加至headNodeC中。headNodeA中的此pa->data元素比较完毕,pa往后移。因为此处的pb->data比较大,还可能与pa->data后面的元素相等,因此pb不动; 
若pb->data比较小,此时还不能判断出此处的pa->data是不是差集中的元素。但因为是递增序列,该pb->data没有必要再与pa->data后面的值相比较。pb往后移,pa不动。*/
	while (pa && pb)
	{
		if (pa->data < pb->data)   
		//因为两个都是递增的单链表,因此此时pa->data一定是差集元素
		{
			pc->next = pa;
			pc = pa;
			pa = pa->next;
			pc->next = NULL;
			count++;
		}
		else if (pa->data > pb->data)  
		{
			pb = pb->next;  
			
//万一pb后面有与pa->data相同的元素,则pa->data一定不是差集元素,进入第三个if判断
//如果pb后面的元素也都比此处的pa->data小,则此处的pa->data一定是差集元素,执行跳出该while循环后面的语句
//如果pb后面的元素出现比此处的pa->data大的,则此处的pa->data也一定是差集元素,执行第一个if判断
		}
		else   //与pa->data相同的元素,则pa->data一定不是差集元素
		{
			pa = pa->next;
			pb = pb->next;
		}
	}

//如果因为pa为NULL,跳出上面的while循环,则不用对pb进行任何处理
/* 如果因为pb为NULL,跳出上面的while循环,且此时pa不等于NULL,由于前面的元素都经过了比较,
则此时pa指向的元素一定是差集元素。如果后面还有,则全部都是差集元素。*/

	if (pa)
	{
		pc->next = pa;
	}

	while (pa)
	{
		count++;
		pa = pa->next;  
//对于单链表,只要头结点定了,各元素之间用指针next相连接,因此此处不用再使用指针pc
	}

	free(headNodeB);

	return count;
}

在这里插入图片描述

习题五

设计算法将一个带头结点的单链表A分解为两个具有相同结构的链表B和C,其中B表的结点为A表中值小于零的结点,而C表的结点为A表中值大于零的结点(链表A中的元素为非零整数,要求B、C表利用A表的结点)。

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};

struct Node* CreateNode(struct Node* headNode);
void insertNodeByTail(struct Node* headNode);
void printNode(struct Node* headNode);
void Dividliist(struct Node* L1, struct Node* L2, struct Node* L3);

int main()
{
	struct Node* listA = NULL;
	struct Node* listB = NULL;
	struct Node* listC = NULL;

	struct Node* list1 = CreateNode(listA);
	struct Node* list2 = CreateNode(listB);
	struct Node* list3 = CreateNode(listC);

	insertNodeByTail(list1);
	printNode(list1);

	printf("\n");
	Dividliist(list1, list2, list3);
	printNode(list2);
	printNode(list3);

	return 0;
}

//创建单链表并进行初始化
struct Node* CreateNode(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;
	return headNode;
}

//后插法往单链表中增加结点
void insertNodeByTail(struct Node* headNode)
{
	struct Node* r = headNode; //指向尾结点
	struct Node* s; //申请的新结点

	int numLength = 0;
	printf("请输入单链表的长度:");
	scanf_s("%d", &numLength);

	int num = 0;

	for (int i = 0; i < numLength; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);

		if (num == 0)
		{
			printf("请输入非0数值。\n");
			i--;
			continue;
		}

		s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;
		s->next = NULL;
		r->next = s;
		r = s;
	}
}

//打印单链表
void printNode(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 0;

	for (i = 1; pMove != NULL; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}

	printf("\nlist_length: %d\n", i);
}

void Dividliist(struct Node* L1, struct Node* L2, struct Node* L3)
{
	/*
		function:将链表L1按元素的正负分为L2和L3两个链表
		参数说明:L1为待分解的链表,L2为负数构成的链表的头结点,L3为正数构成的链表的头结点
	*/

	struct Node* p1 = L1->next;
	struct Node* p2 = L2;
	struct Node* p3 = L3;

	while (p1)
	{
		if (p1->data < 0)
		{
			p2->next = p1;
			p2 = p2->next;
		}
		else if (p1->data > 0)
		{
			p3->next = p1;
			p3 = p3->next;
		}
		p1 = p1->next;
	}

	//L2和L3链表最后一个结点指向NULL
	p2->next = NULL;
	p3->next = NULL;
}

在这里插入图片描述

习题六

设计一个算法,通过一趟遍历确定长度为n的单链表中值最大的结点。

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};

struct Node* CreateNode(struct Node* headNode);
void insertNodeByTail(struct Node* headNode);
void printNode(struct Node* headNode);
struct Node* maxNode(struct Node* headNode);

int main()
{
	struct Node* listA = NULL;

	struct Node* list1 = CreateNode(listA);
	struct Node* max = list1;

	insertNodeByTail(list1);
	printNode(list1);

	printf("\n");
	max = maxNode(list1);
	printf("最大值为:%d", max->data);

	return 0;
}

//创建单链表并进行初始化
struct Node* CreateNode(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;
	return headNode;
}

//后插法往单链表中增加结点
void insertNodeByTail(struct Node* headNode)
{
	struct Node* r = headNode; //指向尾结点
	struct Node* s; //申请的新结点

	int numLength = 0;
	printf("请输入单链表的长度:");
	scanf_s("%d", &numLength);

	int num = 0;

	for (int i = 0; i < numLength; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);
		s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;
		s->next = NULL;
		r->next = s;
		r = s;
	}
}

//打印单链表
void printNode(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 0;

	for (i = 1; pMove != NULL; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}

	printf("\nlist_length: %d\n", i);
}

//寻找最大值
struct Node* maxNode(struct Node* headNode)
{
	struct Node* p = headNode->next;
	struct Node* max = p->next;

	while (p != NULL)
	{
		if (p->data > max->data)
		{
			max = p;
		}

		p = p->next;
	}

	return max;
}

在这里插入图片描述

习题七

设计一个算法,将链表中所有结点的链接方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求算法的空间复杂度为O(1)。

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};

struct Node* CreateNode(struct Node* headNode);
void insertNodeByTail(struct Node* headNode);
void printNode(struct Node* headNode);
void Inverse(struct Node* headNode);

int main()
{
	struct Node* listA = NULL;

	struct Node* list1 = CreateNode(listA);
	struct Node* max = list1;

	insertNodeByTail(list1);
	printNode(list1);

	printf("\n");
	Inverse(list1);
	printNode(list1);

	return 0;
}

//创建单链表并进行初始化
struct Node* CreateNode(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;
	return headNode;
}

//后插法往单链表中增加结点
void insertNodeByTail(struct Node* headNode)
{
	struct Node* r = headNode; //指向尾结点
	struct Node* s; //申请的新结点

	int numLength = 0;
	printf("请输入单链表的长度:");
	scanf_s("%d", &numLength);

	int num = 0;

	for (int i = 0; i < numLength; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);
		s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;
		s->next = NULL;
		r->next = s;
		r = s;
	}
}

//打印单链表
void printNode(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 0;

	for (i = 1; pMove != NULL; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}

	printf("\nlist_length: %d\n", i);
}

// 链表逆转算法(头插法的思想)
void Inverse(struct Node* headNode)
{
	struct Node* p = headNode->next;
	struct Node* q;  //工具结点,防止断链

	headNode->next = NULL;//将头结点的指针域记为空,从首元结点就开始头插法

    while (p != NULL) 
	{
        q = p->next; //工具结点,指向要进行头插法的p结点的下一个结点,防止断链

		//对p结点进行头插法(总是将p指向的结点放到头结点headNode的后面)
        p->next = headNode->next; //改变p指向结点的指针域
		headNode->next = p;  //改变头结点headNode的指针域

        p = q; //此时p要后移,不能再通过p->next,要使用工具指针q保存的结点
    }
}

在这里插入图片描述

习题八

设计一个算法,删除递增有序链表中值大于mink且小于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同)。

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};

struct Node* CreateNodeByTail(struct Node* headNode);
void printNode(struct Node* headNode);
void  Dlelte_Between(struct Node* headNode);

int main()
{
	struct Node* listA = NULL;

	struct Node* list1 = CreateNodeByTail(listA);
	printNode(list1);

	printf("\n");
	Dlelte_Between(list1);
	printNode(list1);

	return 0;
}

//后插法创建一个递增的单链表
struct Node* CreateNodeByTail(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;

	struct Node* s; //申请的新结点

	int numLength = 0;
	printf("请输入单链表的长度:");
	scanf_s("%d", &numLength);

	int i = 0;
	int num = 0;
	struct Node* pre = headNode;
	struct Node* p = headNode->next;

	for (i = 0; i < numLength; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);

		//遍历已存入的数值
		pre = headNode;
		p = headNode->next;
		while (p && p->data < num)
		{
			pre = p;
			p = p->next;
		}

		if (p && p->data == num)
		{
			printf("已存在该数值,请重新输入。\n");
			i--;
			continue;
			//中止本次for循环。
			//跳过本次for循环体中剩下尚未执行的语句,立即进行下一次的for循环
			//continue、break都只对一层循环起作用,用在内层循环时,只对内层循环其作用,对外层循环无影响。
		}

		s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;

		//找到第一个比num大的数p->data,将新结点s插入到p前面
		if (p && p->data > s->data)
		{
			s->next = p;
			pre->next = s;
		}

		if (!p)  //s->data是最大的
		{
			pre->next = s;
			s->next = NULL;
		}
	}

	return headNode;
}

//打印单链表
void printNode(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 0;

	for (i = 1; pMove != NULL; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}

	printf("\nlist_length: %d\n", i);
}


//删除递增有序链表中值大于mink且小于maxk的所有元素(等于mink或maxk的均保留)
void  Dlelte_Between(struct Node* headNode)
{
	int mink = 0;
	int maxk = 0;
	printf("请输入下限:");
	scanf_s("%d", &mink);

	printf("请输入上限:");
	scanf_s("%d", &maxk);

	struct Node* pre = headNode;
	struct Node* p = headNode->next;
	struct Node* q;
	struct Node* s;

	while (p && p->data <= mink)
	{
		pre = p;
		p = p->next;   // 查找第一个值>mink的结点
	}

	if (p)
	{
		while (p && p->data < maxk)
			p = p->next;    // 查找第一个值 ≥maxk的结点

		q = pre->next;  // 修改指针
		pre->next = p;   // 连接链表未被删除的部分

		while (q != p)
		{
			s = q->next;
			delete q;
			q = s;    // 释放结点空间
		}
	}
}

在这里插入图片描述

习题九

已知p指向双向循环链表中的一个结点,其结点结构为data、prior、next三个域,写出算法change(§,交换p所指向的结点及其前驱结点的顺序。

#include <stdio.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* piror;
	struct Node* next;
};

struct Node* Initialization(struct Node* headNode);
void insertNode(struct Node* headNode);
void printlist(struct Node* headNode);
struct Node* inverselist(struct Node* HNode);
struct Node* change(struct Node* hNode);


int main()
{
	struct Node* list1 = NULL;
	struct Node* list2 = NULL;
	struct Node* head11 = NULL;
	struct Node* head22 = NULL;

	struct Node* head1 = Initialization(list1);
	insertNode(head1);
	printlist(head1);

	printf("\n改变所有结点的顺序:");
	head11 = inverselist(head1);
	printlist(head11);

	struct Node* head2 = Initialization(list2);
	insertNode(head2);
	printlist(head2);

	printf("\n改变指定结点与其前驱结点的顺序\n");
	head22 = change(head2);
	printlist(head22);
}

//创建双向循环链表并进行初始化
struct Node* Initialization(struct Node* headNode)
{
	headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->piror = headNode;
	headNode->next = headNode;
	return headNode;
}

//后插法插入结点
void insertNode(struct Node* headNode)
{
	int num = 0;
	int len = 0;
	struct Node* r = headNode;

	printf("请输入双向链表的长度:");
	scanf_s("%d", &len);

	for (int i = 0; i < len; i++)
	{
		printf("请输入第%d个数值:", i + 1);
		scanf_s("%d", &num);

		struct Node* s = (struct Node*)malloc(sizeof(struct Node));
		s->data = num;

		s->piror = r;
		s->next = headNode;
		r->next = s;
		headNode->piror = s;

		r = s;
	}
}

//打印
void printlist(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	int i = 1;

	while (pMove != headNode)  //注意双向循环链表中的结束条件
	{
		printf("%d ", pMove->data);
		i++;
		pMove = pMove->next;
	}

	printf("\nlist_lenth : %d\n", i);
}

//更改链表中所有结点的顺序指向(交换p所指向的结点及其前驱结点的顺序)
struct Node* inverselist(struct Node* HNode)
{
	struct Node* p = HNode->next->next;
	struct Node* q; //工具指针,防止断链

	//类似前插法
	while (p != HNode)  //注意双向循环链表中的结束条件
	{
		q = p->next;
		p->piror->next = p->next;
		p->next->piror = p->piror;

		p->next = HNode->next;
		HNode->next->piror = p;
		p->piror = HNode;
		HNode->next = p; //这个一定要放在最后

		p = q;
	}

	return HNode;
}


//交换指针p所指向的结点及其前驱结点的顺序
struct Node* change(struct Node* hNode)
{
	struct Node* p = hNode->next;
	struct Node* pre; //工具指针

	int num = 0;

	printf("请输入要交换的结点数值:");
	scanf_s("%d", &num);

	//双向循环链表的按值查找
	while (p != hNode && p->data != num)
	{
		p = p->next;
	}

	if (p == hNode && p->data != num)
	{
		printf("不存在该数值,请重新输入。\n");
		hNode = change(hNode);
	}

	if (p != hNode && p->data == num)
	{
		pre = p->piror;

		pre->next = p->next;
		p->next->piror = pre;

		p->piror = pre->piror;
		p->next = pre;
		pre->piror->next = p;
		pre->piror = p;
	}

	return hNode;
}

在这里插入图片描述

习题十

已知长度为n的线性表A采用顺序存储结构,请写一个时间复杂度为O(n)、空间复杂度为O(1)的算法,该算法可删除线性表中所有值为item的数据元素。

abtgu

#include <stdio.h>

//顺序表的存储结构
#define MAXSIZE 100    //顺序表可能达到的最大长度
typedef int ElemType;  //自定义数据元素类型

typedef struct
{
    ElemType* elem;    //存储空间的基地址
    int length;        //当前长度,数据元素的个数
}SqList;               //顺序表的结构类型为SqList

//初始化,构造一个空的顺序表L,并输入数据
void InitList(SqList& L)
{
    int len;
    L.elem = new ElemType[MAXSIZE];   //为顺序表分配一个大小为MAXSIZE的数组空间
    if (!L.elem)
    {
        printf("Error");
        return;
    }

    printf("Please input the length of the linear table:");
    scanf_s("%d", &len);
    L.length = len;


    printf("Please input the elements of the linear table:\n");
    for (int i = 0; i < len; i++)
    {
        scanf_s("%d", &L.elem[i]);  //一个换行符代表一个数值输入结束
    }    
}

//删除值为item的元素
//将非item的数值依次写入
void ListDelete(SqList& L, int item)
{
    int j = 0;
    for (int i = 0; i < L.length; i++)
    {
        if (L.elem[i] != item)
        {
            L.elem[j] = L.elem[i];
            j++;
        }
    }
    L.length = j;
}

int main()
{
    SqList L;
    int item;
    InitList(L);

    printf("Please input the value of item is:");
    scanf_s("%d", &item);
    ListDelete(L, item);

    printf("After Deletion: ");
    for (int i = 0; i < L.length; i++)
    {
        printf("%d ", L.elem[i]);
    }
       
    return 0;
}

在这里插入图片描述

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值