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

1. 利用顺序栈判断一个字符串是否为对称串。

  • 算法思想:对于字符串str,从头到尾将其所有元素连续进栈,如果所有元素连续出栈产生的序列和str从头到尾的字符依次相同,表示str是一个对称串,返回真;否则表示str不是对称串,返回假
bool Symmtry(ElemType str[]) //判断str是否为对称串
{
	int i;
	ElemType e;
	SqStack* st; //定义顺序栈指针
	InitStack(st); //初始化栈
	for (i = 0; str[i] != '\0'; i++)
	{ 
		Push(st, str[i]); //将str的所有元素进栈
	}
	for (i = 0; str[i] != '\0'; i++) //处理str的所有字符
	{
		Pop(st, e); //返回退栈元素e
		if (str[i] != e) //若e与当前字符串不同表示不是对称串
		{
			DestoryStack(st); //销毁栈
			return false; //返回假
		}
	}
	DestoryStack(st); //销毁栈
		return true; //返回真
}

int main() //主函数
{
	ElemType str[MaxSize] = { "reviver" };
	cout << boolalpha << "字符串是对称串吗?—" << Symmtry(str)<<endl;
	return 0;
}

如果使用链栈:

  • 算法思想:让链表前一半元素依次进栈,当n为偶数时,前一半和后一半的个数相同;当n为奇数时,链表中心结点字符不必比较,移动链表指针到下一字符开始比较。
bool Judge(LinkList L, int n)
{
	int i = 0;
	LNode* p = L->next;
	char a[n/2]; //a字符栈
	for (i = 0; i < n / 2; i++) //链表前一半元素进栈
	{
		a[i] = p->data;
		p = p->next;
	}
	i = i - 1;
	if (n % 2 == 1) p = p->next; //若n是奇数,后移过中心结点
	for(i;i>0;i--)
	{
		if (p->data == a[i]) p = p->next;
		else return false;
	}
	if (i == -1) return false; //栈为空栈
	return true;
}

程序分析:

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

2. 假设以I和O分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,可以操作的序列称为合法序列,否则称为非法序列。判定所给的操作序列是否合法,若合法,返回true、否则返回 false(假定被判定的操作序列已存入一维数组中)。

算法思想:入栈后,栈内元素个数加1;出栈后,栈内元素个数减1,因此可将判定一组出入栈序列是否合法转化为一组由+1、-1组成的序列,它的任意前缀子序列的累加和不小于0(每次出或入栈操作后判断)则合法,否则非法。当入栈出栈操作全部结束后,最后判断栈的终态是否为空。

bool Judge(char str[])
{
	int i = 0, j = 0;
	while (str[j] != '\0')
	{
		switch (str[j])
		{
		case 'I':i++; break;
		case 'O':i--;
		if (i < 0) return false;
		}
		j++;
	}
	if (i == 0) return true;
	else return false;
}

程序分析:

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

3. 设有两个栈s1、s2都采用顺序栈方式,并共享一个存储区[0,…, maxsize-1],为了尽量利用空间,减少溢出的可能,可采用栈顶相向、迎面增长的存储方式。试设计s1、s2有关入栈和出栈的操作算法。

  • 算法思想:栈顶相向、迎面增长的存储方式即共享栈。
#include<stdio.h>
#define maxsize 10
typedef int ElemType;
typedef struct
{
	ElemType data[maxsize];
	int top[2];
}PStack;

void InitStack(PStack &s)
{
	s.top[0] = -1;
	s.top[1] = maxsize;
}

int push(PStack& s, int i, ElemType stacknum)
{
	if (i < 0 || i>1)
	{
		printf("栈号输入不对!");
		exit(0);
	}
	if (s.top[1] - s.top[0] == 1)
	{
		printf("栈已满\n");
		return 0;
	}
	switch (i)
	{
		case 0:
		{
			s.data[++s.top[0]] = stacknum; 
			return 1;
			break;
		}
		case 1:
		{
			s.data[--s.top[1]] = stacknum; 
			return 1;
		}
	}
}

ElemType pop(PStack& s, int i)
{
	if (i < 0 || i>1)
	{
		printf("栈号输入不对!");
		exit(0);
	}
	switch (i)
	{
		case 0:
		{
			if (s.top[0] == -1)
			{
				printf("栈空\n");
				return -1;
			}
			else return s.data[s.top[0]--];
		}
		case 1:
		{
			if (s.top[1] == maxsize)
			{
				printf("栈空\n");
				return -1;
			}
			else return s.data[s.top[1]++];
		}
	}
}

bool DispStack(PStack s, int stacknum)
{
	int i;
	if (s.top[0] == -1 && s.top[1] == maxsize)
	{
		printf("栈为空\n");
		return false;
	}
	if(stacknum==0)
	{printf("栈0中的元素为:");
		for (i = 0; i <=s.top[0]; i++)
			printf("%d ", s.data[i]);
		printf("\n");
		printf("栈顶元素为:%d\n", s.data[s.top[0]]);
	}
	else if (stacknum==1)
	{
		printf("栈1中的元素为:");
		for (i = maxsize - 1; i >= s.top[1]; i--)
			printf("%d ", s.data[i]);
		printf("\n");
		printf("栈顶元素为:%d\n", s.data[s.top[1]]);
	}
}

void Input(PStack &s)
{
	int symbol = 1, stacknum;
	ElemType num;
	while(symbol)
	{
		printf("输入0(0号栈)或1(1号栈),或3(退出):\n");
		scanf("%d", &num);
		if (num == 3) break;
		else if (num < 0 || num>1)
		{
			printf("输入错误!\n");
			break;
		}
		if (num==0||num==1)
		{
			printf("请输入元素值:\n");
			scanf("%d", &stacknum);
			if (push(s, num, stacknum) == 0)
			{
				printf("栈已满,无法添加!\n");
				break;
			}
		}
	}
}

int main()
{
	PStack s;
	InitStack(s);
	Input(s);
	DispStack(s, 0);
	DispStack(s, 1);
	printf("共享栈中当前有:%d个元素", maxsize - (s.top[1] - s.top[0]) + 1);
	return 0;
}

程序分析:

  • exit(0):正常运行程序并退出程序; exit(1):非正常运行导致退出程序;
  • return():返回函数,若在主函数中,则会退出函数并返回一值。
  • return返回函数值,是关键字; exit 是一个函数。
    return 0是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束。
  • return是函数的退出(返回);exit是进程的退出。 return是C语言提供的,exit是操作系统提供的(或者函数库中给出的)。
  • return用于结束一个函数的执行,将函数的执行信息传出个其他调用函数使用;exit函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一个状态返回给OS(操作系统),这个状态标识了应用程序的一些运行信息,这个信息和机器和操作系统有关,一般是0 为正常退出,非0 为非正常退出。
  • 非主函数中调用return和exit效果很明显,但是在main函数中调用return和exit的现象就很模糊,多数情况下现象都是一致的。
    在这里插入图片描述
  • 运行结果:在这里插入图片描述

4. 对于环形队列来说,如果知道队头指针和队列中的元素个数,则可以计算队尾指针。也就是说,可以用队列中的元素个数代替队尾指针。设计出这种环形队列的初始化进队出队判队空算法。

  • 算法思想:当已知队列的队头指针front和队列中的元素个数count后,队尾指针rear的计算公式是rear=(front+ count)%MaxSize。因此,这种队列的队空条件为count==0;队满条件为count==Maxsize;元素e的进队操作是先根据队头指针和元素个数求出队尾指针rear,将rear循环增1,然后将元素e放置在rear处;出队操作是先将队头指针循环增1,然后取出该位置的元素。
#include<iostream>
using namespace std;
#include<malloc.h>
#define MaxSize 10
typedef int ElemType;
typedef struct SqQueue
{
	ElemType data[MaxSize];
	int front;
	int count;
};

void InitQueue(SqQueue*& q) //初始化算法
{
	q = (SqQueue*)malloc(sizeof(SqQueue)); //分配空间
	q->count = 0; //队列中的元素个数设置为0
	q->front = 0; //队头指针设置为0
}

bool EmptyQueue(SqQueue *q) //判队空算法
{
	return q->count==0;
}

bool enQueue(SqQueue*& q,ElemType e) //进队算法
{
	int rear; //临时存放队尾指针
	if (q->count == MaxSize) return false;  //队满上溢出
	else
	{
		rear = (q->front + q->count) % MaxSize;
		q->data[rear] = e;
		rear = (rear + 1) % MaxSize;
		q->count++; //元素个数增1
		return true;
	}
}

bool deQueue(SqQueue*& q, ElemType &e) //出队算法
{
	if (q->count == 0) return false; //队空下溢出
	else
	{
		e = q->data[q->front];
		q->count--; //元素个数减1
		q->front = (q->front + 1) % MaxSize; //队头循环增1
		return true;
	}
}

int main()
{
	SqQueue *q;
	InitQueue(q);
	cout << boolalpha << "队列为空吗?—" << EmptyQueue(q) << endl;
	int i;
	for (i = 0; i < MaxSize * 2; i = i + 2) enQueue(q, i);
	cout << boolalpha << "队列为空吗?—" << EmptyQueue(q) << endl;
	ElemType num;
	for (i = 0; i < MaxSize; i++)
	{
		deQueue(q, num);
		cout << num << ' ';
	}
	return 0;
}

程序分析:

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

5. 采用一个不带头结点,只有一个尾结点指针rear的循环单链表存储队列,设计队列的初始化进队出队判队空算法。

#include<iostream>
using namespace std;
#include<malloc.h>
typedef int ElemType;
typedef struct LinkNode
{
	ElemType data;
	struct LinkNode* next;
};
typedef struct LinkQueue
{
	struct LinkNode* rear;
};

void InitQueue(LinkQueue& q) //初始化算法
{
	q.rear = NULL;
}

bool EmptyQueue(LinkQueue q) //判队空算法
{
	return q.rear == NULL;
}

void enQueue(LinkQueue& q, ElemType e) //进队算法
{
	LinkNode* p;
	p = (LinkNode*)malloc(sizeof(LinkNode)); //创建新结点
	p->data = e;
	if (q.rear == NULL) //原链队为空
	{
		p->next = p; //改为循环链表
		q.rear = p; //rear指向新结点
	}
	else //原链队不空
	{
		p->next = q.rear->next; //将p结点插入到rear结点之后
		q.rear->next = p; //改为循环链表
		q.rear = p; //rear指向新结点
	}
}

bool deQueue(LinkQueue& q, ElemType& e) //出队算法
{
	LinkNode* p;
	if (q.rear == NULL) return false; //队空
	else if (q.rear->next == q.rear) //原队中只有一个结点
	{
		e = q.rear->data;
		free(q.rear);
		q.rear = NULL;
	}
	else //原队中有两个或两个以上的结点
	{
		p = q.rear->next; //p指向队头结点
		e = p->data;
		q.rear->next = p->next; //删除p结点
		free(p); //释放结点空间
	}
	return true;
}

int main()
{
	LinkQueue q;
	InitQueue(q);
	cout << boolalpha << "链队为空吗?—" << EmptyQueue(q) << endl;
	int i;
	for (i = 0; i < 20; i = i + 2) enQueue(q, i);
	cout << boolalpha << "链队为空吗?—" << EmptyQueue(q) << endl;
	ElemType num;
	for (i = 0; i < 10; i++)
	{
		deQueue(q, num);
		cout << num << ' ';
	}
	return 0;
}

程序分析:

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

6. Q是一个队列,S是一个空栈,实现将队列中的元素逆置。

#include<iostream>
using namespace std;
#include<malloc.h>
#define MaxSize 10
typedef int ElemType;
typedef struct Stack
{
	ElemType data[MaxSize];
	int top;
};

typedef struct Queue
{
	ElemType data[MaxSize];
	int front, rear;
	int count; //记录队列中元素的个数
};

void InitStack(Stack& s)
{ s.top = -1; }

void InitQueue(Queue& q)
{ 
	q.front = q.rear = 0; 
	q.count = 0;
}

bool Push(Stack& s, ElemType e)
{
	if (s.top == MaxSize - 1) return false;
	else
	{
		s.data[++s.top] = e;
		return true;
	}
}

bool enQueue(Queue& q, ElemType e)
{
	if (q.count==MaxSize) return false;
	else q.data[q.rear++] = e;
	q.count++;
	return true;
}

bool Pop(Stack& s, ElemType& e)
{
	if (s.top == -1) return false;
	else e = s.data[s.top--];
	return true;
}

bool deQueue(Queue& q, ElemType& e)
{
	if (q.count==0) return false;
	else e = q.data[q.front++];
	q.count--;
	return true;
}

bool EmptyStack(Stack s)
{ return s.top == -1; }

bool EmptyQueue(Queue q)
{ return q.front == q.rear; }

int main()
{
	Stack s;
	InitStack(s);
	cout << boolalpha << "栈为空吗?—" << EmptyStack(s) << endl; //初始化,此时栈中没有元素
	Queue q;
	InitQueue(q);
	cout << boolalpha << "队列为空吗?—" << EmptyQueue(q) << endl; //初始化,此时队列中没有元素
	int i;
	ElemType num;
	for (i = 1; i <= MaxSize; i++)
	{
		enQueue(q, i); //元素入队
		deQueue(q, num); //元素出队
		cout << num<<' '; //输出出队元素
		Push(s, num); //将出队元素入栈
	}
	cout << "\n";
	cout << boolalpha << "栈为空吗?—" << EmptyStack(s) << endl; //此时队列中的元素全部入栈,队列为空
	q.rear = q.front = 0; //将front、rear再次置为0
	for (i = 1; i <= MaxSize; i++)
	{
		Pop(s, num); //元素出栈
		enQueue(q, num); //元素重新入队
		deQueue(q, num); //元素重新出队
		cout << num << ' ';
	}
	cout << "\n";
	cout << boolalpha << "栈为空吗?—" << EmptyStack(s) << endl; //此时栈中元素全部入队,栈为空
	cout << boolalpha << "队列为空吗?—" << EmptyQueue(q) << endl; //队列为空
	return 0;
}

程序分析:

  • !注意: 程序第86行要将front、rear重新置0。因为有一个元素入队,rear会加1;有一个元素出队,front会减1。而队列中的元素个数依靠count来统计,此时与front、rear无关。当第一轮元素入队、出队结束后,front、rear均为10。因此第二轮元素需要入队、出队时,首先要把front、rear置为0!!!
  • 运行结果:
    在这里插入图片描述

7. 设从键盘输入一序列的字符 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an。若 a i a_i ai为数字字符, a i a_i ai进队;若 a i a_i ai为小写字母,将队首元素出队,若 a i a_i ai为其他字符,表示输入结束。

  • 算法思想:先建立一个环形队列,用while循环接收用户的输入,根据题目的要求,队列中只可能出现数字字符。
void fun()
{
	ElemType a, e;
	SqQuene *q;
	InitQueue(q);
	while (true)
	{
		printf("输入a:");
		scanf("%s", &a);
		if (a >= '0' && a <= '9')
		{
			if (!enQuene(q, a)) printf("队列满,不能进队\n");
		}
		else if (a >= 'a' && a <= 'z')
		{
			if (!deQueue(q, e)) printf("队列空,不能出队\n");
			else printf("出队元素:%c\n", e);
		}
		else break;
	}
	DestoryQueue(q);
}

程序分析:

  • !注意:程序第九行%s。
  • 运行结果:
    在这里插入图片描述

8. 将一个环形队列(容量为m,元素下标从0到n-1)的元素倒置。

  • 算法思想:使用一个临时栈s,先将q队列中的所有元素出队并将其进桟栈s,直到队列空为止。然后初始化队列q(队列清空),再出栈s的所有元素并将其进队q最后销毁栈s。
  • 与第六题类似!
void fun(SqQueue *&q,SqStack *&s)
{
	int num;
	while (!EmptyQueue(q)) //队不空时出队并入栈
	{
		deQueue(q, num);
		Push(s, num);
	}
	printf("\n");
	InitQueue(q); //队列初始化
	while (!StackEmpty(s)) //栈不空时出栈并将元素入队
	{
		Pop(s, num);
		enQueue(q, num);
	}
	Destroy(s);
}

程序分析:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值