为了训练阅读代码的能力,本篇文章的所有代码都不作详细注释。
实验要求:
构造一个顺序存储的栈,要求至少能够完成如下操作:将元素压入栈顶、将栈顶元素弹出、获取栈顶元素、清除栈。
参考代码及简要注释:
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;
}
}