C语言-实现一个简易的银行排号叫号系统_linzi_1988的博客-程序员秘密_银行叫号系统c语言

技术标签: C语言  单链表  简单排号机  C语言学习  

这两天在网上看到这个题目,感觉挺有意思,就做了一下。我在网上看到其他人都是用C++做的,因为不懂C++语言,没看懂,尝试着用C语言做了该题。希望能来看该题的大神指点指点,估计还有些bug没找出来。

本人编程基础差,利用闲暇的时间来做此题,总时间加在一起,花了一天左右吧。网上有人花了半小时做完该题,让我膜拜啊,太佩服。

进入正题吧,题目要求如下: 实现一个简易的银行排号叫号系统

get    取号                               示例:"get"或"get vip"
call   叫号                                示例:"call"
delete 删除号码                       示例:"delete 5"
count  获取当前排队总人数      示例:"count"
countN 获取号码N以前的排队人数  示例:"countN"
reset  重置排号机                     示例:"reset"
quit   退出排号机                     示例:"quit"
运行时间限制: 无限制
内存限制: 无限制
输入:
每行只会有一条输入(比如:C语言可使用gets函数获取一行输入命令的字符串)。
a、若输入不符合要求(如:命令字非法,或其他认为输入的错误)均需输出"error"
b、每条输出后使用换行符隔开(如后面示例)
输出:
1、取号。可获取普通号和vip号码。如初始状态,输入"get",则获取普通号码,执行结果为"1",如再次输入"get vip",则获取VIP号码,执行结果为"vip 2"。如果末尾的2号被删除,则再次调用"get"时应输出"2"。VIP号码有绝对的优先级。普通号和vip号码统一编号,取号均为连续号码。号码从1开始编号,最大为100000.
2、叫号。获取当前应该处理用户的号码。例如当前排队号码为1 2 3 4 5 7,当输入"call",执行结果为"1",如1为vip号码,则为"vip 1".如果再连续调用6次,第六次执行结果应为"error"

3、删除号码。客户不想办理时可删除号码,叫号时则跳过此号码。例如当前排队号码为1 2 3 4 5,输入"delete 5",执行结果为"5",如果5为vip则显示"vip 5"。再次输出"delete 5",执行结果为"error"

4、获取当前排队总人数。获取当前排队人数。例如当前排队号码为1 2 3 4 5 6,执行结果为"6"

5、获取在某个号码之前排队的总人数。例如当前排队号码为1 2 3 4 5 7,输入"countN 7",执行结果为"5"
6、重置排号机。例如输入"reset",则重置排号机,进入初始状态,无需输出。
7、退出排号机。例如输入"quit",则退出排号机,无需输出。
样例输入:
get
get
get
get vip
count
countN 1
call
quit
样例输出:
1
2
3
vip 4
4
1

vip 4

本人实现的思路:构造一个数据链表,用data存当前的位号,vip表示是否为vip号码(1:是,0:否)然后构造相应操作的子函数,来对整个链表进行操作。也曾想过用数组的方式来实现,但想了一会没想出来,还是觉得用链表的方式实现要方便一些。

typedef struct Node{
	int data;
	int vip;
	struct Node *next;
}Node,*pNode;

对于终端命令的输入,采用gets()和strtok()函数来处理。

在各子函数处理时,要注意题目的一些要求。稍微复杂一点的函数是叫号call和删除delete函数,这两种情况都要对最后一个节点单独处理,另外取号get需要考虑vip的情况。所以的子函如下所示,包括命令解析、链表头初始化、相应的操作函数。

pNode InitList(void);
int command(pNode pHead, char *substr1, char *substr2);
pNode get(pNode pHead,int vip);
pNode call(pNode pHead);
int delete_num(pNode pHead, int num);
int count(pNode pHead);
int countN(pNode pHead,int num);
int reset(pNode pHead);
int quit(pNode pHead);

在输出error格式上,调试时为了知道是哪里的error,并没有按照题目的格式要求输出,加了位置信息。另外一点题目要求排号上限不超过100000,本人作答时没有考虑该条件。如果需要加条件限制的话,就在get函数中加一个判断GetNumFlag的语句即可。

附上完整的源码:

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

/***********************************
定义链表结构体,用来存号、存VIP标志
************************************/
typedef struct Node{
	int data;
	int vip;
	struct Node *next;
}Node,*pNode;

#define VIP 1
#define NOTVIP 0	//宏定义VIP的标志位
int GetNumFlag=0; //定义的全局变量,用来存储取号的数量,避免没人取号的情况下call完所有人后从1开始计数。

pNode InitList(void);
int command(pNode pHead, char *substr1, char *substr2);
pNode get(pNode pHead,int vip);
pNode call(pNode pHead);
int delete_num(pNode pHead, int num);
int count(pNode pHead);
int countN(pNode pHead,int num);
int reset(pNode pHead);
int quit(pNode pHead);

/***********************************************************************************
功能:主函数main
************************************************************************************/
int main()
{
	char Str[20],StrBack[20];
	char *substr1,*substr2;
	pNode pHead=NULL;

	pHead=InitList();

	while(1){
		gets(Str);
		substr1=strtok(Str," ");
		substr2=strtok(NULL," ");

		if(command(pHead, substr1,substr2) == -1){
			break;
		}
	}
	return 0;
}

/***********************************************************************************
功能:解析命令函数
传入参数:pHead是链表头结点,substr1是命令第1个字串,substr2是命令第2个字串
返回值:正常返回0;返回-1时,表示收到了quit命令,退出排号机
************************************************************************************/
int command(pNode pHead, char *substr1, char *substr2)
{
	int countNum=0;

	if(substr1 == NULL){
		printf("input error\n");
		return 0;
	}
	if(strcmp(substr1,"get")==0){
		if(substr2 != NULL ){
			if(strcmp(substr2,"vip")==0){
				get(pHead,VIP);
			}else 
				printf("input error\n");
		}else
			get(pHead,NOTVIP);
	}else if(strcmp(substr1,"call")==0){
		call(pHead);
	}else if(strcmp(substr1,"delete")==0){
		if(substr2 != NULL ){
			delete_num(pHead, (int)atol(substr2));
		}else
			printf("input error\n");
	}else if(strcmp(substr1,"count")==0){
		countNum=count(pHead);
		printf("the count is: %d\n",countNum);
	}else if(strcmp(substr1,"countN")==0){
		if(substr2 != NULL ){
			countNum=countN(pHead, (int)atol(substr2));
			if(countNum == -1)
				printf("input N is error\n",countNum);
			else
				printf("the countN is: %d\n",countNum);
		}else
			printf("input error\n");
	}else if(strcmp(substr1,"reset")==0){
		reset(pHead);
	}else if(strcmp(substr1,"quit")==0){
		quit(pHead);
		return -1;
	}else
		printf("input error\n");
	return 0;
}

/***********************************************************************************
功能:初始化链表头
传入参数:无
返回值:返回链表头指针pHead,如果初始化失败,则返回NULL指针
************************************************************************************/
pNode InitList(void)
{
	pNode pHead = NULL;

	pHead = (pNode)malloc(sizeof(Node));
	if(pHead == NULL){
		printf("fail to init list!\n");
		return NULL;
	}
	pHead->data=0;
	pHead->vip=0;
	pHead->next=NULL;

	return pHead;
}

/***********************************************************************************
功能:取号
传入参数:链表头指针pHead,vip为vip客户标志
返回值:返回链表头指针pHead,如果初始化失败,则返回NULL指针
************************************************************************************/
pNode get(pNode pHead,int vip)
{
	pNode pNew,pTemp;

	pTemp = pHead;

	while(pTemp->next !=NULL){
		pTemp = pTemp->next;
	}
/****注意这里的可能错误,申请的内存是结构体的内存,pNode是指针,sizeof(pNode)为4,是指针的大小。因此在free的时候会出现程序崩溃,反而在申请内存和赋值时是没问题的,需要注意****/
//	pNew = (pNode)malloc(sizeof(pNode));  
	pNew = (pNode)malloc(sizeof(Node));
	if(pNew == NULL){
		printf("fail to create pNew!\n");
		return NULL;
	}
	pTemp->next = pNew;
	pNew->next = NULL;
	pNew->data = ++GetNumFlag;
//	pNew->data = pTemp->data+1;   //用这种情况,就会出现当call完所有数据后,get时从1开始计数,我猜银行系统会避免这种情况
	if(vip==1){
		pNew->vip = 1;
		printf("get vip %d\n",GetNumFlag);
	}else{
		pNew->vip = 0;
		printf("get %d\n",GetNumFlag);
	}
	return pNew;
}

/***********************************************************************************
功能:叫号,如果为vip需要输出vip标志
传入参数:链表头指针pHead
返回值:返回链表头指针pHead,如果所有号被叫完,再次叫号则返回NULL指针
************************************************************************************/
pNode call(pNode pHead)
{
	pNode pTemp;
	pNode pTempFront;

	if(pHead->next == NULL){
		printf("output error,number is over\n");
		return NULL;
	}
	pTempFront = pHead;
	pTemp = pHead->next;
	while(pTemp->next != NULL || pTemp->vip ==VIP){   //首先获取VIP号码,注意当最后一个号为VIP的情况,不能跳过
		if(pTemp->vip == VIP){
			printf("this is vip: %d\n",pTemp->data);
			if(pTemp->next !=NULL)
				pTempFront->next = pTemp->next;
			else
				pTempFront->next = NULL;
			free(pTemp);
			pTemp = NULL;
			return pHead;
		}else{
			pTempFront = pTemp;
			pTemp = pTemp->next;
		}
	}
	pTempFront = pHead;
	pTemp = pHead->next;
	printf("this is call: %d\n",pTemp->data);
	pTempFront->next = pTemp->next;
	free(pTemp);
	pTemp = NULL;
	return pHead;
}

/***********************************************************************************
功能:删除号码
传入参数:链表头指针pHead,num为需要删除的号码
返回值:成功返回0,如果未找到输出error并返回-1
************************************************************************************/
int delete_num(pNode pHead, int num)
{
	int i=0;
	pNode pTempFront,pTemp;
	pTempFront=pHead;
	pTemp=pTempFront->next;

	while(pTemp->next != NULL){
		if(pTemp->data == num ){
			if(pTemp->vip == VIP){
				printf("delete the num: vip %d\n",pTemp->data);
			}else
				printf("delete the num: %d\n",pTemp->data);
			pTempFront->next = pTemp->next;
			free(pTemp);
			pTemp = NULL;
			return 0;
		}else{
			pTemp=pTemp->next;
			pTempFront=pTempFront->next;
		}
	}
	if(pTemp->data == num ){			 //这里要要判断最后一个节点,最后一个节点的处理有点区别,注意题目要求
		if(pTemp->vip == VIP){
			printf("delete the num: vip %d\n",pTemp->data);
		}else
			printf("delete the num: %d\n",pTemp->data);
		pTempFront->next = pTemp->next;
		free(pTemp);
		pTemp = NULL;
		GetNumFlag--;      //这里要注意,题目要求:如果末尾的2号被删除,则再次调用"get"时应输出"2"
		return 0;
	}else{
		printf("error,input number is not match\n");
		return -1;
	}
}

/***********************************************************************************
功能:获取当前排队总人数
传入参数:链表头指针pHead
返回值:返回当前排队总人数count
************************************************************************************/
int count(pNode pHead)
{
	int count=0;
	pNode pTemp=pHead;

	while(pTemp->next != NULL){
		count++;
		pTemp=pTemp->next;
	}
	return count;
}

/***********************************************************************************
功能:获取N号以前的排队人数
传入参数:链表头指针pHead
返回值:返回N号以前的排队人数count,如果没有此号或者已经删除了此号,输出error,返回-1
************************************************************************************/
int countN(pNode pHead,int num)
{
	int count=0;
	pNode pTemp=pHead->next;

	while(pTemp->data != num){
		count++;
		if(pTemp->next == NULL){
			printf("error\n");
			return -1;
		}
		pTemp=pTemp->next;
	}
	return count;
}

/***********************************************************************************
功能:重置排号机,释放存号的节点,不能释放头结点pHead
传入参数:链表头指针pHead
返回值:返回0
************************************************************************************/
int reset(pNode pHead)
{
	pNode pTemp=pHead->next;

	while(pHead->next != NULL){
		pHead->next=pTemp->next;
		free(pTemp);
		pTemp=pHead->next;
	}
	GetNumFlag=0;
	return 0;
}

/***********************************************************************************
功能:退出排号机,释放存号的节点,并且释放头结点pHead
传入参数:链表头指针pHead
返回值:返回0
************************************************************************************/
int quit(pNode pHead)
{
	reset(pHead);
	free(pHead);
	return 0;
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/linzi_1988/article/details/79574792

智能推荐

HDU 5726 GCD(RMQ+二分,详解,ST算法)_David_Jett的博客-程序员秘密

题目链接:HDU 5726题面:GCDTime Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1151    Accepted Submission(s): 354Problem Description

Spark的RDD转换算子-value型-coalesce、 repartition 、sortBy_牧码文的博客-程序员秘密

Spark的RDD转换算子-value型-coalesce、 repartition 、sortBy一、coalesce函数签名def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T] 根据数据量缩减分区,用于大数据集过滤后,提高小数据集的执行效率 当 spark 程序中,存在过多的小任务的时候,可以通过 coalesce 方法,收缩合并分区,减少分区的个数,减小任务调度成本val rdd = sp

专业背单词的好软件_梦想田园的博客-程序员秘密

英语单词的记忆在英语学习中有着举足轻重的地位,可以说一个人掌握的单词量越多,英语水平就越高;而英语单词的记忆除了需要长时间不断地积累外,还需要高效的记忆方法。随着人们生活节奏的加快,人们也更希望通过信息技术可以用最短的时间记住最多的单词。也正是因为这样的需求,市面上出现了大量的背单词软件,虽然这些软件功能强大看起来也很气派,但是大部分都是通过各种手段来让人不断重复记忆的,并未以科学的方法从根本上解...

程序员进步指南:从每一天少写一点 code 开始_weixin_34252686的博客-程序员秘密

Google 与网络的帮助可以让你写出一行又一行的代码。不过,若你只是复制贴上,事后并没有尝试了解背后的运作机制,充其量代表了「工作完成」。那有什么办法可以让自己进步呢?也许你可以从少写一点代码开始。并不是要你不工作,而是想办法精简自己的代码。在某些方面,coding 跟写作有些类似,并不是多就是好,正如马克吐温说的:我没有时间写一封简短的信,所以我...

运行APUE代码前的一些配置_夜阳羽的博客-程序员秘密

原文:http://www.cnblogs.com/rockics/archive/2010/12/20/1911784.htmlAPUE中的代码不是download下来就可以直接编译执行的。由于头文件的问题,需要做相关的设置,修改一下相关的文件。首先从http://www.apuebook.com/src.tar.gz下载源码压缩包,解压到相应目录,例如:mkdir /h

[Python] L1-038. 新世界 团体程序设计天梯赛GPLT_柳婼的博客-程序员秘密

这道超级简单的题目没有任何输入。你只需要在第一行中输出程序员钦定名言“Hello World”,并且在第二行中输出更新版的“Hello New World”就可以了。PS:感谢github用户@zhuzihao-hz提供的pull request~print('Hello World')print('Hello New World') ...

随便推点

S7-1200 PLC之间进行TCP通信的具体方法和步骤详解_使用kepserver 与s7-1200plc建立通信连接的具体方法和步骤.docx_AAA_自动化工程师的博客-程序员秘密

S7-1200 PLC之间进行TCP通信的具体方法和步骤详解本次以一个1214 CPU和一个1215 CPU为例进行说明TCP通信的具体方法,其中1214作为发送端,1215作为接收端(也可以双方同时进行发送和接收,这里只是简单举例说明)如下图所示,新建一个项目,添加一个1214 CPU和1215CPU,双击“设备和网络”,选择“网络视图”,点击“连接”,选择“TCP连接”,如下图所示,如下图所示,直接用鼠标拖拽PN接口将2个CPU连接起来,松开即可,选中1214 CPU,进入属性—常规—

jqGrid入门 中文文档 参数方法讲解(自我备用)_weixin_30408675的博客-程序员秘密

JqGrid中文文档最近使用JQGrid 发现其中文资料非常的少。几乎没有,而英文资料大部份是PHP。所以写一些资料方便自己和大家以后的使用。先来看一个我在官方网站复制的简单的例子。 1: &lt;%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default3.aspx.cs" Inherits=...

Python错误集锦: NameError: name ‘numpy’ is not defined_桔子code的博客-程序员秘密

原文链接:http://www.juzicode.com/archives/2225错误提示:使用numpy.eye()函数时报NameError: name ‘numpy’ is not definedD:\juzicode&gt;python mod.py 微信公众号: 桔子code / juzicode.com Traceback (most recent call last): File "mod.py", line 3, in n = numpy.eye(4)

Linux 虚拟文件系统四大对象:超级块、inode、dentry、file之间关系_linux中超级块、inode、目录项_一口Linux的博客-程序员秘密

一:文件系统1. 什么是文件系统?操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。通常文件系统是用于存储和组织文件的一种机制,便于对文件进行方便的查找与访问。文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。随着文件种类的增多,扩增了更多的文件系统,为了对各种文件系统进行统一的管理与组织。2. Linux文件系统Linux将文件系

stm32f769discovery 寄存器配置ETH,无操作系统移植lwip141_malinda666的博客-程序员秘密

一直以来都想搞个寄存器配置版本的ETH,最近时间充裕,花了近2周,昨天终于实现了以太网的连接,上图 捕获.JPG (28.93 KB, 下载次数: 0)下载附件  保存到相册 2018-3-23 10:48 上传 这是打印结果 下面详细说明一下 首先实现lan8742的驱动/* Ethernet pins configuration ********************************...

推荐文章

热门文章

相关标签