【数据结构实验】顺序栈、顺序(线性)队列、循环队列DEMO

为了训练阅读代码的能力,本篇文章的所有代码都不作详细注释。

一、顺序栈

实验要求:
构造一个顺序存储的栈,要求至少能够完成如下操作:将元素压入栈顶、将栈顶元素弹出、获取栈顶元素、清除栈。
参考代码及简要注释:
1、push 和 pop 动作都会返回一个 bool 变量,1 代表操作成功,0 代表操作失败。
2、本表通过构造一系列随机数来完成对顺序栈的操作的演示。
3、当栈满时再做进栈运算必定产生空间溢出,简称“上溢”;
当栈空时再做退栈运算也将产生溢出,简称“下溢”。
上溢是一种出错状态,应该设法避免之。
下溢是正常现象,因为栈在程序中使用时,其初态或终态大多数时候都是空栈,所以下溢常常用来作为程序控制转移的条件。

#include
#include
#include
#pragma warning(disable:4996)
typedef unsigned long long ull; typedef unsigned uint;
const ull lmax = 64;
template<typename t> struct SqStack { t* bottom = nullptr, * top; ull size; };
template<typename t> inline void InitSqStack(SqStack<t> &s){
	s.bottom = (t*)malloc(sizeof(t) * lmax), s.top = s.bottom - 1, s.size = 0;
}
template<typename t> inline void ClearSqStack(SqStack<t> &s){
	if (s.bottom != nullptr) { free(s.bottom), InitSqStack(s); }
}
template<typename t> inline bool PushIntoSqStack(SqStack<t> &s, const t& value){
	if (s.size == lmax)return false;
	++s.size, ++s.top, * s.top = value; return true;
}
template<typename t> inline bool PopFromSqStack(SqStack<t> &s){
	if (s.size == 0)return false;
	--s.size, --s.top; return true;
}
template<typename t> inline t TopOfSqStack(const SqStack<t> &s){
	return *s.top;
}
int main(){
	SqStack<uint> s; std::uniform_int_distribution<uint> u(0, 9999), v(1, 128), w(1, 64); std::default_random_engine d; d.seed(clock()); uint n, e;
	InitSqStack(s);
	for (;;) {
		n = v(d); for (uint i = 0; i < n; ++i) {
			e = u(d);
			switch (PushIntoSqStack(s, e)) {
			case true:printf("Pushed the element %u to S. The top element of sequential stack s is: %u\n", e, TopOfSqStack(s)); continue;
			case false:puts("Sequential stack s is full. Push operation failed.");
			}
		}
		printf("Size of sequential queue S = %llu\n", s.size);
		n = w(d); for (uint i = 0; i < n; ++i) {
			printf("The top element of sequential stack s is: %u\n", TopOfSqStack(s));
			switch (PopFromSqStack(s)) {
			case true:puts("A pop of sequential stack s just happened."); continue;
			case false:puts("Sequential stack s is already empty.");
			}
		}
		printf("The size of sequential queue S = %llu\n", s.size);
		ClearSqStack(s);
		printf("Tried clearing the sequential stack s. The size of sequential queue S = %llu\n", s.size);
		puts("If you wanna continue please input any character. Or input EOF (Ctrl + Z).");
		if (getchar() == EOF)return 0;
	}
}

二、顺序队列

实验要求:
构造一个顺序队列(线性队列),要求至少能够完成如下操作:将元素从队尾压入、将元素从队首弹出、获取队首元素、获取队尾元素、清除全部元素。
参考代码及其简要注释:
1、push 和 pop 动作都会返回一个 bool 变量,1 代表操作成功,0 代表操作失败。
2、本表通过构造一系列随机数来完成对顺序栈的操作的演示。
3、队列中亦有上溢和下溢现象。此外,顺序队列中还存在“假上溢”现象。因为在入队和出队的操作中,头尾指针只增加不减小,致使被删除元素的空间永远无法重新利用。因此,尽管队列中实际的元素个数远远小于存储空间的规模,但也可能由于尾指针巳超出存储空间的上界而不能做入队操作。该现象称为假上溢。

#include
#include
#include
#pragma warning(disable:4996)
typedef unsigned long long ull; typedef unsigned uint;
const ull lmax = 64;
template<typename t> struct SqQueue { t* begin = nullptr, * end, *front, * back; ull size = 0; };
template<typename t> inline bool PushIntoSqQueue(SqQueue<t>& q, const t& value) {
	if (q.begin == nullptr) { q.begin = (t*)malloc(sizeof(t) * lmax), q.end = q.begin + lmax - 1, q.front = q.begin, q.back = q.front, *q.back = value, ++q.size; return true; }
	else if (q.end == q.back)return false;
	if (q.front != q.back)++q.back;
	*q.back = value, ++q.size; return true;
}
template<typename t> inline bool PopFromSqQueue(SqQueue<t>& q) {
	if (q.size == 0)return false;
	else if (q.front == q.back) { --q.size; return true; }
	++q.front, --q.size; return true;
}
template<typename t> inline t FrontOfSqQueue(const SqQueue<t>& q) {
	return *q.front;
}
template<typename t> inline t BackOfSqQueue(const SqQueue<t>& q) {
	return *q.back;
}
template<typename t> inline void ResetSqQueue(SqQueue<t>& q) {
	if (q.begin != nullptr) { free(q.begin), q.size = 0, q.begin = nullptr; }
}
int main() {
	SqQueue<uint> q; std::uniform_int_distribution<uint> u(0, 9999), v(1, 128), w(1, 64); std::default_random_engine d; d.seed(clock()); uint n, e;
	for (;;) {
		n = v(d);
		for (uint i = 0; i < n; ++i) {
			e = u(d);
			switch (PushIntoSqQueue(q, e)) {
			case true:printf("%u has been pushed into sequential queue q.\nThe front and back element of q are: %u, %u\n", e, FrontOfSqQueue(q), BackOfSqQueue(q)); continue;
			case false:puts("The back pointer has got to the end of the authorized memory declared by malloc.");
			}
		}
		printf("The size of sequential queue q = %llu\n", q.size), n = w(d);
		for (uint i = 0; i < n; ++i) {
			if (q.size != 0)printf("The front and back element of q are: %u, %u\n", FrontOfSqQueue(q), BackOfSqQueue(q));
			switch (PopFromSqQueue(q)) {
			case true:puts("A pop operation has been completed in sequential queue q."); continue;
			case false:puts("Sequential queue q is already empty or The back pointer has got to the end of the authorized memory declared by malloc.");
			}
		}
		printf("The size of sequential queue q = %llu\n", q.size);
		ResetSqQueue(q), printf("The size of sequential queue q = %llu\n", q.size);
		puts("If you wanna continue please input any character. Or input EOF (Ctrl + Z).");
		if (getchar() == EOF)return 0;
	}
}

三、循环队列

实验要求:
构造一个循环队列,要求至少能够完成如下操作:将元素从队尾压入、将元素从队首弹出、获取队首元素、获取队尾元素、清除全部元素。
参考代码及其简要注释:
1、push 和 pop 动作都会返回一个 bool 变量,1 代表操作成功,0 代表操作失败。
2、本表通过构造一系列随机数来完成对顺序栈的操作的演示。
3、为充分利用存储空间,需克服假上溢现象。方法是将存储单元想象为一个首尾相接的圆环,并称为循环存储单元,存储在其中的队列称为循环队列(Circular Queue)。在循环队列中进行出队、入队操作时,头尾指针仍要加1,朝前移动。只不过当头尾指针指向存储单元上界时,其加1操作的结果是指向存储单元的下界0。

#include
#include
#include
#pragma warning(disable:4996)
typedef unsigned long long ull; typedef unsigned uint;
const ull lmax = 64;
template<typename t> struct LoopQueue { t* begin = nullptr, * end, * front, * back; ull size = 0; };
template<typename t> inline bool PushIntoLoopQueue(LoopQueue<t>& q, const t& value) {
	if (q.size == lmax)return false;
	if (q.front == q.back) { *q.back = value, ++q.size; return true; }
	if (q.back == q.end) { q.back = q.begin, q.back = q.begin, ++q.size; return true; }
	++q.back, ++q.size, * q.back = value; return true;
}
template<typename t> inline bool PopFromLoopQueue(LoopQueue<t>& q) {
	if (q.size == 0)return false;
	if (q.front == q.back) { --q.size; return true; }
	if (q.back == q.begin) { q.back = q.end, --q.size; return true; }
	--q.back, --q.size; return true;
}
template<typename t> inline t FrontOfLoopQueue(const LoopQueue<t>& q) {
	return *q.front;
}
template<typename t> inline t BackOfLoopQueue(const LoopQueue<t>& q) {
	return *q.back;
}
template<typename t> inline void ResetLoopQueue(LoopQueue<t>& q) {
	if (q.begin != nullptr) { free(q.begin), q.size = 0; }
	q.begin = (t*)malloc(sizeof(t) * lmax), q.front = q.begin, q.back = q.begin, q.end = q.begin + lmax - 1;
}
int main() {
	LoopQueue<uint> q; std::uniform_int_distribution<uint> u(0, 9999), v(1, 128), w(1, 64); std::default_random_engine d; d.seed(clock()); uint n, e;
	for (;;) {
		ResetLoopQueue(q), printf("The size of loop queue q is %llu\n", q.size);
		n = v(d);
		for (uint i = 0; i < n; ++i) {
			e = u(d);
			switch (PushIntoLoopQueue(q, e)) {
			case true:printf("%u is pushed into loop queue q. The front and the back of q are: %u %u\n", e, FrontOfLoopQueue(q), BackOfLoopQueue(q)); continue;
			case false:puts("Loop queue q is full.");
			}
		}
		printf("The size of loop queue q is %llu\n", q.size);
		n = w(d);
		for (uint i = 0; i < n; ++i) {
			printf("The front and the back of q are: %u %u\n", FrontOfLoopQueue(q), BackOfLoopQueue(q));
			switch (PopFromLoopQueue(q)) {
			case true:puts("A pop operation has happened in loop queue q."); continue;
			case false:puts("Loop queue q is empty.");
			}
		}
		printf("The size of loop queue q is %llu\n", q.size);
		puts("If you wanna continue please input any character. Or input EOF (Ctrl + Z).");
		if (getchar() == EOF)return 0;
	}
}

你可能感兴趣的:(基础课,#,数据结构)