以客房管理系统为例实现链表的基本操作

以客房管理系统为例实现链表的基本操作(C语言)

个人体验

敲完这段数据结构作业的代码后,我加深了对指针赋值操作的理解;在减少时间复杂度的目的下放弃了冒泡排序,第一次实现了插入排序;学会了新方法来寻找链表中点,以减少时间复杂度。

需求

(1)实现创建客房信息链表函数void Build(HLink &H),输入(客房名称、标准价格、床位数),同时修改入住价格、入住状态为默认值,即入住价格=标准价格*80%,入住状态为”空闲”(提示:用strcpy()字符串拷贝函数)。为了提高程序调试效率,要求:必须用文件操作来输入客房信息(客房名称、标准价格、床位数);
(2)实现输出客房信息函数void Exp(HLink H),输出所有客房的客房名称、标准价格、入住价格、床位数、入住状态;
(3)函数int Find(HLink &H, char *roomN),查找房间名称为roomN的客房。如果找到,则返回该客房在链表中的位置序号(>=1),否则返回0。提示:用strcmp()字符串比较函数;
(4)实现函数void updateH(HLink &H, int beds, char *state),将床位数为beds的客房入住状态改为state。提示:用strcpy()字符串拷贝函数;
(5)函数void Add(HLink &H),将该链表中未入住的客房入住价格均加价20%;
(6)求出入住价格最高的客房函数HLink FirstH(HLink &H),该函数内return语句返回入住价格最高的客房结点指针,返回前将该结点在链表中删除;
(7)函数void MoveK1(HLink &H, int k),将单链表中倒数第k个结点移到第一个结点位置,注意:严禁采用先计算链表长度n再减k(即n-k)的方法;
(8)函数void ReverseN2(HLink &H),将单链表的正中间位置结点之后的全部结点倒置的功能,注意:严禁采用先计算链表长度n再除以2(即n/2)的方法;
(9)函数void SortPriceL(HLink &H),按照客房(入住价格,客房名称)升序排序;
(10)函数void upBed(HLink &H,int beds),创建一个【床位数为beds的新结点】(还需输入:客房名称、标准价格等信息),使链表的形态为:【头结点】->【床位数>beds的结点】->【床位数为beds的新结点】->【床位数<=beds的结点】,要求【超过beds的结点】和【不超过beds的结点】这两段链表中的结点保持原来的前后相对顺序;
(11)主函数main()调用以上函数,(3)若返回值>=1则输出该客房在链表中的位置序号,否则输出该客房不存在;输出(4)~(10)处理后的链表内容,其中(6)还要输出入住价格最高的客房信息。

代码演示

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//定义客房链表结点结构
typedef struct HNode
{
	char	roomN[7];	//客房名称
	float   Price;		//标准价格
	float   PriceL;	//入住价格(默认值=标准价格*80%)
	int	   Beds;		//床位数Beds
	char	   State[5];	//入住状态(值域:"空闲"、"入住"、"预订",默认值为"空闲")
	struct HNode  *next;	//指针域
}Hotel, *HLink;
int main()
{													//函数声明
	void Build(HLink &H);							//*创建客房信息链表
	void Exp(HLink H);								//*输出客房信息
	int Find(HLink &H, char *roomN);				//*查找房间名称为roomN的客房
	void updateH(HLink &H, int beds, char *state);	//*将床位数为beds的客房入住状态改为state
	void Add(HLink &H);								//*将链表中未入住的客房入住价格均加价20%
	HLink FirstH(HLink &H);							//*返回入住价格最高的客房结点指针,返回前将该结点在链表中删除
	void MoveK1(HLink &H, int k);					//*将单链表中倒数第k个结点移到第一个结点位置
	void ReverseN2(HLink &H);						//*将单链表的正中间位置结点之后的全部结点倒置
	void SortPriceL(HLink &H);						//*按照客房(入住价格,客房名称)升序排序;前者优先级高于后者
	void upBed(HLink &H, int beds);					//*创建一个【床位数为beds的新结点】;【头结点】->【床位数>beds的结点】->【床位数为beds的新结点】->【床位数<=beds的结点】
													//函数声明	
	HLink H;
	Build(H);

	{							//(3)
		int result;
		char roomN[7] = "8201";	//查找房间名为8201的位置序号
		printf("(3)\n");
		result = Find(H, roomN);
		if (result == 0) {
			printf("该客房不存在\n");
		}
		else if (result >= 1) {
			printf("房间在链表中的位置序号:%d\n", result);
		}
		else
			printf("程序错误!\n");
	}
	printf("\n客房信息(客房名称、标准价格、入住价格、床位数、入住状态)输出如下:\n");
	printf("--------------------------------------------------------------------\n");
	printf("客房名称\t标准价格\t入住价格\t床位数\t入住状态\n");
	printf("--------------------------------------------------------------------\n");
	{						//(4)
		char State[5]="入住";	
		int beds = 2;
		printf("(4)\n");
		printf("将床位数为 2 的客房入住状态改为“入住”\n");
		updateH(H,beds,State);//将床位数为 2 的客房入住状态改为“入住”
		Exp(H);
	}
	{						//(5)
		printf("(5)\n");
		printf("未入住的客房入住价格均加价20%\n");
		Add(H);				//未入住的客房入住价格均加价20%
		Exp(H);
	}
	{						//(6)
		HLink max = (HLink)malloc(sizeof(HNode));
		max->next= FirstH(H);//获取入住价格最高的客房对应的指针
		printf("(6)\n");
		printf("入住价格最高的客房:\n");
		Exp(max);
		printf("删除最高价客房后的链表:\n");
		Exp(H);
	}
	{						//(7)
		int last = 3;
		printf("(7)\n");
		printf("将倒数第3个结点移到第一个结点位置\n");
		MoveK1(H,last);				//倒数第3个结点移到第一个结点位置
		Exp(H);
	}
	{						//(8)
		printf("(8)\n");
		ReverseN2(H);				//将单链表的正中间位置结点之后的全部结点倒置
		Exp(H);
	}
	{						//(9)
		printf("(9)\n");
		printf("按照客房(入住价格,客房名称)升序排序;前者优先级高于后者\n");
		SortPriceL(H);				//按照客房(入住价格,客房名称)升序排序;前者优先级高于后者
		Exp(H);
	}
	{						//(10)
		int beds = 7;
		printf("(10)\n");
		printf("添加一个床位数为7的客房,客房的其他信息通过文件addata.txt输入或自动补全\n");
		upBed(H,beds);				//添加一个床位数为7的客房,客房的其他信息通过文件addata.txt输入或自动补全
		Exp(H);
	}

	system("pause");
	return 0;
}

void Build(HLink &H)
{							//构造一个链表并读取文件的数据
	Hotel* rear;
	Hotel* p;
	FILE *infile;
	infile = fopen("indata.txt", "r");				//打开文本文件"indata.txt"
	H = (HLink)malloc(sizeof(HNode));  
	rear = H;
	//依次从文本文件中读取结点数据(客房名称、标准价格、床位数)
	while (!feof(infile))	//判断是否读取到文件结尾
	{
		p = (HLink)malloc(sizeof(HNode));
		fscanf(infile, "%s%f%d\n", p->roomN, &p->Price, &p->Beds);//从文件中逐行读取客房名称、标准价格、床位数
		p->PriceL = p->Price*0.8;
		strcpy(p->State, "空闲");
		rear->next = p;
		rear = p;
	}
	rear->next = NULL;
	fclose(infile);
}

void Exp(HLink L)							//遍历链表L,输出从首元结点到尾结点储存的所有客房信息
{
	HLink p;
	p = L->next;
	while (p) {
		printf("%-16s", p->roomN);
		printf("%-16f", p->Price);
		printf("%-16f", p->PriceL);
		printf("%-8d", p->Beds);
		printf("%-s\n", p->State);
		p = p->next;
	}
}

int Find(HLink &H, char*roomN)
{
	int n = 0;
	HLink p;
	p = H->next;
	while (p)
	{
		n++;
		if (strcmp(p->roomN, roomN))			//若p->room和 roomN一样,则strcmp函数返回0,否则返回非0
		{
			p = p->next;
			if (!p)
			{
				n = 0;
				break;
			}
		}
		else									//若p->room和 roomN一样,则挑出循环,返回n后结束函数运算
			break;
	}
	return n;
}

void updateH(HLink &H, int beds, char *state)
{
	HLink p;
	p = H->next;
	while (p)									//遍历链表H
	{
		if (p->Beds == beds)					//若找到既定的床位数,则把p->state改为既定的字符串state
		{
			strcpy(p->State, state);
		}
		p = p->next;
	}
}

void Add(HLink &H)
{
	HLink p;
	p = H->next;
	while (p)									//遍历链表H
	{
		if (strcmp(p->State, "入住"))			//若找到p->state值为“入住”时,p->PriceL的值增加20%
		{
			p->PriceL = p->PriceL*1.2;
		}
		p = p->next;
	}
}

HLink FirstH(HLink &H)
{
	HLink max, p, pre, maxpre;			//pre是p的前驱,maxpre是max的前驱
	max = H->next;
	maxpre = max;
	p = H->next;
	pre = p;
	while (p)							//用指针变量p遍历链表H
	{
		if (p->PriceL > max->PriceL)	//用指针变量max存储最大结点位置
		{
			max = p;
			maxpre = pre;
		}
		pre = p;
		p = p->next;
	}
	maxpre->next = max->next;
	max->next = NULL;					//将最大值对应的结点从链表H中独立出来
	return max;
}

void MoveK1(HLink &H, int k)
{//默认题中所说的第一个结点位置是首元结点位置
	HLink p = H;				//初始定义p是指向链表H中头结点(而不是首元结点)的指针
	HLink pend = p;			//定义一个终将指向单链表的末端节点的指针
	HLink first, pre = p;
	while (p && (k - 1))			//找到第k个节点,并把该节点的指针赋值给pend
	{
		if (!(pend->next))
		{
			printf("k大于单链表长度,产生溢出!\n");
			exit(0);
		}
		pend = pend->next;
		k--;
	}
	while (pend->next)//将p和pend两个指针沿着链表以相同的速度向后遍历,直到pend指向链表的末端结点
	{
		pre = p;
		p = p->next;
		pend = pend->next;
	}					//此时p指向单链表中倒数第k个结点
	first = H->next;
	H->next = p;
	pre->next = p->next;
	p->next = first->next;//将p移到第一个结点位置
}

void ReverseN2(HLink &H)
{
	printf("将单链表的正中间位置结点之后的全部结点倒置: \n");
	HLink slow, fast, middle;
	fast = H;
	for (slow = H; fast&&fast->next;) {    //fast指针移动速度是slow指针的两倍,因此当fast移动到链表末时slow恰好移动到正中间
		fast = fast->next->next;		   //当fast=NULL时,除头结点外链表结点数为单数,slow指针恰好在正中间位置
		slow = slow->next;				   //当fast->next=NULL时,结点数为偶数,slow指针恰好在前半部分的最后一个结点
	}
	middle = slow;
	HLink half = (HLink)malloc(sizeof(HNode));
	half->next = NULL;
	for (; middle->next; middle = middle->next)//前插法构造后半部分倒序链表,表头结点是half
	{
		HLink p = (HLink)malloc(sizeof(HNode));
		p->Beds = middle->next->Beds;
		p->Price = middle->next->Price;
		p->PriceL = middle->next->PriceL;
		strcpy(p->roomN, middle->next->roomN);
		strcpy(p->State, middle->next->State);
		p->next = half->next;
		half->next = p;
	}
	slow->next = half->next;//将原结点的前半部分和新生成的half拼接在一起
}

void SortPriceL(HLink &H)			//使用插入排序
{
	HLink sorted, choose, aft;
	sorted = H;
	choose = sorted->next->next;
	sorted->next->next = NULL;
	while (choose) {//若“sorted指针已经遍历到尾结点或者sorted后一个指针存储的信息大于等于choose存储的信息”那么choose结点插入到sorted之后
			if (!sorted->next ||//“sorted存储的信息大于choose”指的是入住价格大或者在入住价格一样时房间号大
				((choose->PriceL < sorted->next->PriceL) ||
				((choose->PriceL == sorted->next->PriceL) && (strcmp(choose->roomN, sorted->next->roomN) < 0)))) {
				aft = choose->next;
				choose->next = sorted->next;
				sorted->next = choose;
				choose = aft;
				sorted = H;
			}
			else {
				sorted = sorted->next;
			}
	}
}

void upBed(HLink &H, int beds)				//客房名称、标准价格通过文件addata.txt输入
{
	HLink up = (HLink)malloc(sizeof(HNode));
	HLink L = (HLink)malloc(sizeof(HNode));
	HLink p, rear, N;
	{	//该程序块的功能是从addata.txt文件中读取客房名称、标准价格,再结合函数输入的床位数,把其余信息按同样的规则补齐,存储在L中
		Hotel* p;
		FILE *infile;
		infile = fopen("addata.txt", "r");				//打开文本文件"addata.txt"
		rear = L;										//文件中的数据存储在链表L中

		//依次从文本文件中读取结点数据(客房名称、标准价格)
		while (!feof(infile))	//判断是否读取到文件结尾
		{
			p = (HLink)malloc(sizeof(HNode));
			fscanf(infile, "%s%f\n", p->roomN, &p->Price);//从文件中逐行读取客房名称、标准价格
			p->PriceL = p->Price*0.8;
			strcpy(p->State, "空闲");
			p->Beds = beds;
			rear->next = p;
			rear = p;
		}
		rear->next = NULL;
		fclose(infile);
	}
	N = up;
	for (p = H->next; p; p = p->next) {//对于已有的链表H,床位数大于beds的结点存储在链表up中,小于或等于beds的结点按原来的顺序接在链表L之后
		if (p->Beds > beds) {
			N->next = p;
			N = N->next;
		}
		else if (p->Beds <= beds) {
			rear->next = p;
			rear = rear->next;
		}
	}
	rear->next = NULL;
	N->next = L->next;					//链表L从首元结点到尾结点接在链表up之后
	H = up;								//链表up的头指针传给变量H
}

用于调试的两个文本文档

indata.txt

8101	100	1
8102	100	4
8103	150	2
8201	200	1
8202	200	1
8203	200 1
8204	200	1
8205	200	5
8206	2   1
8207	200	1
8208	200	3
8209	200 1

addata.txt

8301	800

猜你喜欢

转载自blog.csdn.net/weixin_45720773/article/details/106506952