《数据结构》上机实验(第三章)——栈和队列 Ⅱ

《数据结构》上机实验(第三章) Ⅰ

1. 输入n(由用户输入)个10以内的数,每输入i(0≤i≤9)就把它插入到第i号队列中,最后把10个队中的非空队列按队列号从小到大的顺序串接成一条链,并输出该链的所有元素。

算法思想:建立一个队头指针数组quh和队尾指针数组qut,quh[i]和qut[j]表示i号(0≤i≤9)队列的队头和队尾,先将它们的所有元素置为NULL。对于输入的x,采用尾插法将其链到x号队列中。然后按0~9编号的顺序把这些队列中的结点构成
不带头结点的单链表,其首结点指针为head。最后输出单链表head的所有结点值并释放所有结点。

#include<stdio.h>
#include<malloc.h>
#define MAXQNode 10 //队列的个数
typedef struct QNode
{
	int data;
	struct QNode* next;
};

void Insert(QNode* quh[], QNode* qut[], int x) //将x插入到相应的队列中
{
	QNode* s;
	s = (QNode*)malloc(sizeof(QNode));
	s->data = x;
	s->next = NULL;
	if (quh[x] == NULL)
	{
		quh[x] = s;
		qut[x] = s;
	}
	else
	{
		qut[x]->next = s;
		qut[x] = s;
	}
}

void Create(QNode* quh[], QNode* qut[]) //根据用户的输入创建队列
{
	int n, x;
	printf("n:");
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		do {
			printf("输入第%d个数:", i+1);
			scanf("%d", &x);
		} while (x<0||x>10);
		Insert(quh, qut, x);
	}
}

void DestroyList(QNode*& head) //释放单链表
{
	QNode* pre = head, * p = pre->next;
	while(p!=NULL)
	{
		free(pre);
		pre = p;
		p = p->next;
	}
	free(pre);
}

void DisplayList(QNode* head) //输出单链表的所有结点值
{
	printf("\n输出所有元素:");
	while (head != NULL)
	{
		printf("%d ", head->data);
		head = head->next;
	}
	printf("\n");
}

QNode* Link(QNode* quh[], QNode* qut[]) //将非空队列链接起来并输出
{
	QNode* head = NULL, * tail; //总链表的首结点指针和尾结点指针
	for (int i = 0; i < MAXQNode; i++) //扫描所有队列
		if (quh[i] != NULL) //i队列不空
		{
			if(head==NULL) //若i号队列为第一个非空队列
			{
				head = quh[i];
				tail = qut[i];
			}
			else //若i号队列不是第一个非空队列
			{
				tail->next = quh[i];
				tail = qut[i];
			}
		}
	tail->next = NULL;
	return head;
}

int main()
{
	QNode* head;
	QNode* quh[MAXQNode], * qut[MAXQNode];
	for (int i = 0; i < MAXQNode; i++) quh[i] = qut[i] = NULL;
	Create(quh, qut);
	head = Link(quh, qut);
	DisplayList(head);
	DestroyList(head);
	return 0;
}

程序分析

在这里插入图片描述

  • 运行结果:
    在这里插入图片描述
    在这里插入图片描述

2. 将一个十进制正整数d转换为相应的二进制数

  • 算法思想:将十进制正整数转换成二进制数通常采用除2取余数法。在转换过程中,二进制数是按照从低位到高位的次序得到的,这和通常的从高位到低位输出二进制的次序相反。为此设计一个栈s用于暂时存放每次得到的余数,当转换过程结束时,退栈所有元素便得到从高位到低位的二进制数。
void trans()
{
	LinkStNode* s;
	InitStack(s);
	int n, num;
	printf("输入一个十进制正整数:");
	scanf("%d", &num);
	do {
		Push(s, num % 2);
		num = num / 2;
	} while (num);
	while (!StackEmpty(s))
	{
		Pop(s, n);
		printf("%d", n);
	}
	DestoryStack(s);
}

程序分析

  • 运行结果:
    在这里插入图片描述

3. 设计一个算法,利用顺序栈的基本运算从栈顶到栈底输出栈中的所有元素,要求仍保持栈中元素不变。

  • 算法思想:先建立并初始化一个临时temp。退栈s中的所有元素,输出这些元素并进栈到temp中,然后将临时栈temp中的元素逐一出栈并进栈到s中,这样恢复s栈中原来的元素。
void diverse()
{
	LinkStNode* s, * temp;
	InitStack(s); InitStack(temp);
	int n, num;
	printf("输入:");
	scanf("%d", &num);
	while (num != 999)
	{
		s->data = num;
		Push(s, s->data);
		scanf("%d", &num);
	}
	while (!StackEmpty(s))
	{
		Pop(s, n);
		printf("%d ", n);
		Push(temp, n);
	}
	while (!StackEmpty(temp))
	{
		Pop(temp, n);
		Push(s, n);
	}
	DestoryStack(temp);
}

程序分析

  • !注意本题要求只能使用栈的基本运算来完成,不能直接用st->data[i]输出栈中的元素。
  • 运行结果:
    在这里插入图片描述

4. 利用顺序栈的基本运算求找中从栈顶到栈底的第k个元素,要求仍保持栈中元素不变。

-算法思想:先建立并初始化一个临时栈temp。退栈s中的所有元素x,并用i累计元素个数,当i==k时,将所有元素进栈到temp中,然后将临时栈temp中的元素逐出栈并进栈到s中,这样恢复s栈中原来的元素。如果中没有第k个元素,返回假;否则返回真。

bool diverse(int k)
{
	LinkStNode* s, * temp;
	InitStack(s); InitStack(temp);
	int n, num;
	printf("输入:");
	scanf("%d", &num);
	while (num != 999)
	{
		s->data = num;
		Push(s, s->data);
		scanf("%d", &num);
	}
	for (int i = 0; i < k; i++)
	{
		Pop(s, s->data);
		
		Push(temp, s->data);
		printf("%d ", s->data);
	}
	if (StackEmpty(s))
	{
		printf("\n栈中不存在第%d个元素", k);
		return false;
	}
	else
	{
		while (!StackEmpty(temp))
		{
			Pop(temp, n);
			Push(s, n);
		}
		return true;
	}
	DestoryStack(temp);
}

//printf("\n栈中有第k个元素吗?—%d",diverse(5));

程序分析

  • !注意本题要求只能使用栈的基本运算来完成,不能直接用st->data[i]求第k个栈中元素。
  • 运行结果:
    在这里插入图片描述

5. 有abcde共n(n=5)个字符,通过一个栈可以产生多种出栈序列,判断序列str是否为一个合适的出栈序列,并给出操作过程,要求用相关数据进行测试。

  • 算法思想:先建立一个字符顺序栈s,将进栈序列abcde存放到字符数组A中。用i、j分别扫描数组A和str,它们的初始值均为0。当数组A和str都没有扫描完时循环:比较栈顶元素e和str[j],若两者不相同,则将A[i]进栈,i加1;若两者相同,则出栈栈顶元素e,j加1。上述循环结束后退栈所有元素,如果序列str是一个合适的出栈序列,必有j==n,否则str不是一个合适的出栈序列。
bool isSerial(char str[])
{
	LinkStNode* s;
	InitStack(s); 
	char A[MaxSize], e;
	int  i, j = 0, k = 0;
	for (i = 0; i < strlen(str); i++)
		A[i] = 'a'+i;
	while (j < strlen(str) && k < strlen(str))
	{
		if (StackEmpty(s) || (GetTop(s, e) && e != str[k]))
		{
			Push(s, A[j]);
			printf("元素%c进栈\n", A[j]);
			j++;
		}
		else
		{
			Pop(s, e);
			printf("元素%c出栈\n", e);
			k++;
		}
	}
	while (!StackEmpty(s) && (GetTop(s, e)) && e == str[k])
	{
		Pop(s, e);
		printf("元素%c出栈\n", e);
		k++;
	}
	DestoryStack(s);
	if (k == strlen(str)) return true;
	else return false;
}

void Display(char str[])
{
	for (int i = 0; i < strlen(str); i++)
		printf("%c", str[i]);
}

int main()
{
	char str[6] = { "acbde" };
	Display(str);
	printf("的操作序列:\n");
	if (isSerial(str))
	{
		Display(str);
		printf("是合适的出栈序列\n");
	}
	else
	{
		Display(str);
		printf("不是合适的出栈序列\n");
	}
	return 0;
}

程序分析

{ ① 栈 s 为 空 , A [ i ] 元 素 直 接 入 栈 ② 栈 s 不 为 空 , 获 取 栈 顶 元 素 的 值 , 如 果 该 值 与 s t r [ j ] 的 值 不 相 等 , 则 将 栈 顶 元 素 出 栈 \begin{cases} ①栈s为空,A[i]元素直接入栈\\ ②栈s不为空,获取栈顶元素的值,如果该值与str[j]的值不相等,则将栈顶元素出栈\\ \end{cases} {sA[i]sstr[j]

  • 运行结果:
    在这里插入图片描述

6. 利用环形队列的基本运算返回指定队列中的队尾元素,要求算法的空间复杂度为O(1)。

  • 算法思想:先求出队列q中的元素个数count,循环count次,出队一个元素num,再将元素num进队,最后的num即为队尾元素。
ElemType Last(CyQueue& q)
{
	ElemType num;
	int count = (q.rear - q.front + MaxSize) % MaxSize;
	for (int i = 0; i < count; i++)
	{
		deQueue(q, num);
		enQueue(q, num);
	}
	return num;
}

程序分析

  • 由于算法要求空间复杂度为O(1),所以不能使用临时队列。
  • 运行结果:
    在这里插入图片描述

7. 删除队列中从队头开始的第k个元素的算法。

  • 算法思想:先求出队列q中的元素个数count,若k小于0或大于count,返回假。出队所有元素,并记录元素的序号i,当i=k时对应的元素只出不进,否则将出队的元素又进队。
bool Delete(CyQueue& q, int k)
{
	ElemType num;
	int count = (q.rear - q.front + MaxSize) % MaxSize;
	if (k<0 || k>count) return false;
	for (int i = 0; i < count; i++)
	{
		deQueue(q, num);
		if (i != k) enQueue(q, num);
	}
	return true;
}

程序分析

  • 运行结果:
    在这里插入图片描述

8. 假设有一个整型数组存放n个学生的分数,将分数分为3个等级,分数高于或等于90的为A等,分数低于60的为C等,其他为B等。要求采用双端队列,先输出A等分数,再输出C等分数,最后输出B等分数。

  • 算法思想:设计双端队列的从队头出队算法deQueue1、从队头进队算法enQueue1和从队尾进队算法 enQueue2。对于含有n个分数的数组a,扫描所有元素a[i],若a[i]为A等,直接输出;若为B等,将其从队尾进队;若为C等,将其从队头进队。最后从队头出队并输出所有的元素。
bool enQueue1(DQueue& q, ElemType e) //从队头入队
{
	if ((q.rear + 1) % MaxSize == q.front) return false; //队满
	q.data[q.front] = e; //e元素入队
	q.front = (q.front -1+ MaxSize) % MaxSize; //修改队头指针
	return true;
}

bool enQueue2(DQueue& q, ElemType e) //从队尾进队算法
{
	if ((q.rear + 1) % MaxSize == q.front) return false; //队满
	q.rear = (q.rear + 1) % MaxSize; //修改队尾指针
	q.data[q.rear] = e; //e元素入队
	return true;
}

bool deQueue1(DQueue& q, ElemType &e) //从队头出队
{
	if (q.rear == q.front) return false; //队空
	q.front = (q.front + 1) % MaxSize; //修改队头指针
	e = q.data[q.front];
	return true;
}

void fun(int a[], int n)
{
	ElemType e;
	DQueue q;
	InitQueue(q);
	for(int i=0;i<n;i++)
	{
		if (a[i] >= 90) printf("%d ", a[i]);
		else if (a[i] >= 60) enQueue2(q, a[i]); //从队尾进队
		else enQueue1(q, a[i]); //从队头进队
	 }
	while (!EmptyQueue(q))
	{
		deQueue1(q, e); //从队头出队
		printf("%d ", e);
	}
	printf("\n");
}

程序分析

  • 运行结果:
    在这里插入图片描述

9. 用于列车编组的铁路转轨网络是一种栈结构,其中右边轨道是输入端、左边轨道是输出端。当右边轨道上的车皮编号顺序为1、2、3、4时,如果执行操作进栈、进栈、出栈、进栈、进栈、出栈、出栈、出栈,则在左边轨道上的车皮编号顺序为2、4、3、1。

设计一个算法,输入n个整数,表示右边轨道上n节车皮的编号,用上述转轨栈对这些车皮重新编排,使得编号为奇数的车皮都排在编号为偶数的车皮的前面。
在这里插入图片描述

  • 算法思想:将转轨栈看成一个栈,将左边轨道看成是一个队列。从键盘逐个输入表示右边轨道上车皮编号的整数,根据其奇偶性做以下处理:若是奇数,则将其插入到表示左边轨道的顺序队列的队尾;若是偶数,则将其插入到表示转轨栈的顺序栈的栈顶。当n个整数都检测完之后,这些整数已全部进入队列或栈中。此时,首先按先进先出的顺序输出队列中的元素,然后再按后进先出的顺序输出中的元素。
    算法中直接使用两个数组st和qu分别存放栈和队列中的元素。
void fun()
{
	SqStack s;
	InitStack(s);
	SqQueue q;
	InitQueue(q);
	int n, x, i;
	ElemType num;
	printf("输入:n=");
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		printf("第%d个车皮编号:", i);
		scanf("%d", &x);
		if (x % 2 == 0)
		{
			Push(s, x);
			printf("%d进栈\n", x);
		}
		else
		{
			enQueue(q, x);
			printf("%d进队\n", x);
		}
	}
	printf("列车出轨操作:\n");
	while (!QueueEmpty(q))
	{
		deQueue(q, num);
		printf("%d出队 ", num);
	}
	while (!StackEmpty(s))
	{
		Pop(s, num);
		printf("%d出栈 ", num);
	}
}

程序分析

  • 运行结果:
    在这里插入图片描述

10. 要求输出迷宫的所有路径,并求第一条最短路径长度及最短路径。

算法思想:Link:栈在迷宫问题中的应用

#include<stdio.h>
#define M 8 //行数
#define N 8 //列数
#define Maxsize 100 //栈最多元素个数
int mg[M + 2][N + 2] = { //ー个迷宫, 其四周加上均为1的外框
	{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},
	{1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},
	{1,0,1,1,1,0,0,0,0,1},{1,0,0,0,1,0,0,0,1},
	{1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},
	{1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1} };
struct
{
	int i, j;
	int di;
}St[Maxsize], Path[Maxsize]; //定义栈和存放最短路径的数组
int top = -1; //栈顶指针	
int count = 1; //路径数计数
int minlen = Maxsize; //最短路径长度

void dispapath() //输出一条路径并求最短路径
{
	int k;
	printf(" %5d: ", count++); //输出第count条路径
	for (k = 0; k <= top; k++)
		printf("(%d,%d)", St[k].i, St[k].j);
	printf("\n");
	if (top + 1 < minlen) //比较找最短路径
	{
		for (k = 0; k <= top; k++) //将最短路径存放在path中
			Path[k] = St[k];
		minlen = top + 1; //将最短路径长度存放在minlen中
	}
}

void dispminpath() //输出第一条最短路径
{
	printf("最短路径如下:\n");
	printf("长度:%d\n", minlen);
	printf("路径:");
	for (int k = 0; k < minlen; k++)
		printf("(%d,%d)", Path[k].i, Path[k].j);
	printf("\n");
}

void mgpath(int xi, int yi, int xe, int ye)//求迷宫路径
{
	int i, j, i1, j1, di;
	bool find;
	top++; //进栈
	St[top].i = xi;
	St[top].j = yi;
	St[top].di = -1;
	mg[xi][yi] = -1; //初始方块进栈
	while (top > -1) //栈不空时循环
	{
		i = St[top].i; //取顶方块(i,j)
		j = St[top].j;
		di = St[top].di;
		if (i == xe && j == ye) //找到了出口
		{
			dispapath(); //输出一条路径
			mg[i][j] = 0; //让出口变为其他路径可走方块
			top--; //出口退栈,即回退一个方块
			i = St[top].i;
			j = St[top].j;
			di = St[top].di; //让栈顶方块变为当前方块
		}
		find = false;	//找下一个可走方块(i1,j1)
		while (di < 4 && !find)
		{
			di++;
			switch (di)
			{
			case 0: i1 = i - 1; j1 = j; break;
			case 1: i1 = i; j1 = j + 1; break;
			case 2: i1 = i + 1; j1 = j; break;
			case 3: i1 = i; j1 = j - 1; break;
			}
			if (mg[i1][j1] == 0) find = true;
		}
		if (find)//找到了下一个可走方块(i1,j1)//修改原機顶元素的di值
		{
			St[top].di = di;
			top++;
			St[top].i = i1;
			St[top].j = j1;
			St[top].di = -1; //下一个可走方块(11,j1)进栈
			mg[i1][j1] = -1; //避免重复走到该方块
		}
		else //没有路径可走,则(i,j)方块退栈
		{
			mg[i][j] = 0; //让该位置变为其他路径可走方块
			top--;
		}
	}
	dispminpath(); //输出最短路径
}
					
int main()
{
	printf("迷宫所有路径如下:\n");
	mgpath(1, 1, M, N);
	return 0;
}

程序分析

  • 运行结果:
    在这里插入图片描述
    在这里插入图片描述
  • 10
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值