文章目录
一、模拟小摊的营业情况
(模拟方面并不专业,只是一个思路)
//双向链队列的实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct {
int wait_time;//等待时间
int n;//客人序号
}Item;
typedef struct node {
Item item;
struct node* next;//指向下一个指针
struct node* piror;//指向前一个指针
}Node;
typedef struct {
Node* rear;//队尾指针
Node* front;//队首指针
int node_num;//节点数量
}Queue;
bool InitQueue(Queue* pq);//初始化队列
bool QueueIsEmpty(Queue* pq);//判断队列是否为空
bool QueueIsFull(Queue* pq);//判断队列是否已满
bool InQueue(Queue* pq);//入队
bool OutQueue(Queue* pq);//队首出队
bool FreeQueue(Queue* pq);//释放队列
bool CanNotWait(Queue* pq, Node** pscan);//删除一个节点
void ShowQueue(Queue* pq);//展现队列
void CalculateBudget(Queue* pq);//计算预算
bool InitQueue(Queue* pq)
{
pq->rear = (Node*)malloc(sizeof(Node));
pq->front = (Node*)malloc(sizeof(Node));
pq->node_num = 0;
pq->rear = pq->front;//为队空创造条件
if (pq->rear == NULL)
return false;
if (pq->front == NULL)
return false;
return true;
}
bool QueueIsEmpty(Queue* pq)
{
//队尾就是队头时,说明队空
if (pq->rear == pq->front)
return true;
else return false;
}
bool QueueIsFull(Queue* pq)
{
Node* pnew;
pnew = (Node*)malloc(sizeof(Node));
if (pnew == NULL)
{
free(pnew);
return true;
}
else
{
free(pnew);
return false;
}
}
bool InQueue(Queue* pq)
{
static n = 1;
Node* pnew;
pnew = (Node*)malloc(sizeof(Node));
if (pnew == NULL)
return false;
pnew->item.wait_time = 0;//客人等待时间初始化为0
pnew->item.n = n++;//给客人标上序号
if (QueueIsFull(pq) == true)
{
printf("队列已满,无法入队!\n");
return false;
}
else if (QueueIsEmpty(pq) == true)
{
pq->front->piror = NULL;//队首前面不会排节点
pq->front->next = pnew;//队首之后是新节点
pnew->piror = pq->front;//把新节点排在队首后面,必须在前两条之后实现
pnew->next = NULL;//新节点后面没有节点
pq->rear = pnew;//新节点作为队尾,必须最后实现
}
else
{
pq->rear->next = pnew;
pnew->piror = pq->rear;
pnew->next = NULL;
pq->rear = pnew;
}
pq->node_num++;//节点数量增加
return true;
}
bool OutQueue(Queue* pq)
{
Node* ptemp;
if (QueueIsEmpty(pq) == true)
{
printf("队列为空!出队失败!\n");
return false;
}
else
{
ptemp = pq->front;
pq->front = pq->front->next;
free(ptemp);
pq->node_num--;//节点数量减少
return true;
}
}
bool FreeQueue(Queue* pq)
{
Node* psave;
while (QueueIsEmpty(pq) == false)
{
psave = pq->front;
pq->front = pq->front->next;
free(psave);
}
return true;
}
void ShowQueue(Queue* pq)
{
Node* pscan;
if (QueueIsEmpty(pq) == true)
printf("队列为空!\n");
else
{
//从队头向后遍历
pscan = pq->front->next;//队头本身是没有内容的(Item 没有初始化)
while (pscan != NULL)//rear->next = NULL,rear有内容
{
printf("客人%d:等待时间%d\n", pscan->item.n, pscan->item.wait_time);
pscan = pscan->next;
}
putchar('\n');
//从队尾向前遍历
//pscan = pq->rear;
//while (pscan != pq->front)//front没内容,且不为空指针
//{
// printf("%d ", pscan->item.wait_time);
// pscan = pscan->piror;
//}
}
}
bool CanNotWait(Queue* pq, Node** pscan)
{
Node* ptemp_piror;
Node* ptemp_next;
bool flag1 = false;
bool flag2 = false;
ptemp_piror = (Node*)malloc(sizeof(Node));
ptemp_next = (Node*)malloc(sizeof(Node));
if (ptemp_piror == NULL)
return false;
if (ptemp_next == NULL)
return false;
if ((*pscan)->piror != pq->front)
{
ptemp_piror = (*pscan)->piror;
flag1 = true;
}
if ((*pscan)->next != NULL)
{
ptemp_next = (*pscan)->next;
flag2 = true;
}
//pscan当前指向的节点,前面不是队头,本身不是队尾才实现
//通过flag标记判断
if (flag1 == true && flag2 == true)
{
ptemp_piror->next = ptemp_next;
ptemp_next->piror = ptemp_piror;
(*pscan) = ptemp_next;//pscan地址向后更新
pq->node_num--;
return true;
}
//如果psacn当前指向队尾
if ((*pscan)->next == NULL)
{
pq->rear = (*pscan)->piror;//pscan前面的节点变成队尾
pq->rear->next = NULL;//队尾节点后面一定是NULL
(*pscan) = pq->rear->next;//因为已经遍历完了,让pscan指向NULL
pq->node_num--;//节点数量减1
return true;
}
return false;
}
//营业额收入预估程序
//摊位每次接待一名顾客,队伍最多排5人,平均每3分钟来1位新顾客
//摊位每次接待需要10分钟,顾客平均等待15分钟就会离队
//每天的摊位费是500元,每次接待的纯利润是5元
//客流量达到多少才能不亏本,每天营业多久才能不亏本,有多少顾客因为队满未入队,有多少顾客因等待过久而离队
void CalculateBudget(Queue* pq)
{
int open_time = 0;//开张时间
int new_guest_time = 3;//每3分钟来一个新客
int serve_time = 5;//招待一个顾客需要8分钟
int all_guest = 0;//来过店铺的顾客量
int max_queuq_value = 5;//最大队伍长度
double profit = 5;//平均接待每个顾客的盈利
double gross_profit = 0;//总盈利额
double cost_price = 500;//成本额
int max_wait_time = 15;//极限等待时间
int queue_full = 0;//因队满而离开
int can_not_wait = 0;//因等待过久而离开
Node* pscan;//遍历用节点指针
int flag = 1;//用于记录招待的时间
while (gross_profit < cost_price)
{
if (QueueIsEmpty(pq) == false)
{
if (flag == 1)
{
printf("开始招待顾客!\n");
flag++;
pq->front->next->item.wait_time = 0;//正在被招待的顾客不会因为等不及而离队
}
else if (flag < serve_time)//还没招待完
{
printf("正在招待顾客!\n");
flag++;
pq->front->next->item.wait_time = 0;
}
else
{
OutQueue(pq);
gross_profit += profit;
printf("招待完一名顾客!\n");
flag = 1;
}
}
if (QueueIsEmpty(pq) == false)
{
pscan = pq->front->next;
while (pscan != NULL)
{
pscan->item.wait_time++;//用遍历让每一位在队列中的顾客的等待时间+1
if (pscan->item.wait_time >= max_wait_time)//超过等待时间离队
{
if (CanNotWait(pq, &pscan) == true)//pscan经过此函数会变化
{
can_not_wait++;//因等不及而离队的顾客+1
printf("顾客等不及,出队!\n");
continue;//跳回循环
}
}
pscan = pscan->next;//没有离队情况下,自动向后遍历
}
}
if (open_time % new_guest_time == 0)//达到要求来新顾客
{
printf("来了一位新顾客!\n");
if (pq->node_num == max_queuq_value)
{
queue_full++;
printf("因为队满而离开了!\n");
}
else
{
InQueue(pq);
printf("成功进队!\n");
}
all_guest++;
}
else
printf("没有新顾客光临!\n");
open_time++;
printf("已经赚了%lf元\n", gross_profit);
ShowQueue(pq);
}
printf("open_time = %d\n", open_time);
printf("all_guest = %d\n", all_guest);
printf("queue_full = %d\n", queue_full);
printf("can_not_wait = %d\n", can_not_wait);
}
int main()
{
Queue Q;
if (InitQueue(&Q) == true)
printf("程序运行……\n");
else
exit(1);
CalculateBudget(&Q);
FreeQueue(&Q);
return 0;
}
二、CanNot Wait()函数参数列表中使用Node** pscan的原因
1. 如果直接将指针作为实参传递
#include<stdio.h>
void fun(int* p)
{
int b = 2;
p = &b;
}
int main(void)
{
int a = 1;
int* p;
p = &a;
printf("p = %p\n", p);
printf("*p = %d\n", *p);
fun(p);
printf("p = %p\n", p);
printf("*p = %d\n", *p);
return 0;
}
结果如下
p = 000000000061FE14
*p = 1
p = 000000000061FE14
*p = 1
发现指针p不论是指向的地址还是指向的值,均未改变
这是因为,和所有变量一样,指针变量也有自己的地址和值
当指针指向某一变量时,指针的值就是这个变量的地址
C Primer Plus P255 - 10.5 指针操作 - 取址
说明将指针p这个变量直接作为实参传递时,就会像普通的变量传递那样
实际参数是具体的值,该值要被赋给作为形式参数的变量。因为被调函数使用的是从主调函数中拷贝而来,所以无论被调函数对拷贝函数进行什么操作,都不会影响主调函数中的原始数据
C Primer Plus P214 - 9.1.6 调用带实际参数的函数
因此我们可以采用,引用类型或指向指针的指针来达到想要的效果
2. 如果将指针的地址作为实参传递(即使用指向指针的指针)
#include<stdio.h>
#include<string.h>
void fun(int** p)
{
int b = 2;
*p = &b;
}
int main(void)
{
int a = 1;
int* p;
p = &a;
printf("p = %p\n", p);
printf("*p = %d\n", *p);
fun(&p);
printf("p = %p\n", p);
printf("*p = %d\n", *p);
return 0;
}
结果如下
p = 000000000061FE1C
*p = 1
p = 000000000061FDDC
*p = 0
发现指针p的地址改变了,但地址中存放的值却不是我们想要的2
(其实地址改变了,也不是我们想要的地址,只是一个随机分配的地址)
这是因为变量b的作用域只在fun()函数当中,离开后便不可用
C Primer Plus P321 - 12.1.1 作用域
将变量b定义为static类型便可正确传递变量
static int b = 2;
p = 000000000061FE1C
*p = 1
p = 0000000000403010
*p = 2