数据结构实验二之栈和队列(上)——顺序栈和链栈

实验题1:实现顺序栈的各种基本运算的算法

题目描述

编写一个程序sqstack.cpp,实现顺序栈(假设栈中的元素类型Elemtype为char)的各种基本运算,并在此基础上设计一个程序exp3-1.cpp完成以下功能。

(1)初始化栈s。

(2)判断栈s是否非空。

(3)依次进栈元素a、b、c、d、e。

(4)判断栈s是否非空。

(5)输出出栈序列。

(6)判断栈s是否非空。

(7)释放栈。

sqstack.cpp程序,其中包含如下函数。

· InitStack(SqStack *&s):初始化顺序栈s。

· DestroyStack(SqStack *&s):销毁顺序栈s。

· StackEmpty(SqStack*s):判断顺序栈s是否为空栈。

· Push(SqStack *&s,ElemType e):元素e进顺序栈。

· Pop(SqStack *&s,ElemType &e):元素e出顺序栈。

· GetTop(SqStack *s,ElemType &e):取顺序栈的栈顶元素e。

运行代码

sqstack.cpp
#include<iostream>
using namespace std;
#include<stdio.h>
#include<malloc.h>
#define Maxsize 100
typedef char Elemtype;
typedef struct {
	Elemtype data[Maxsize];
	int top;
}SqStack;
//初始化顺序栈
void InitStack(SqStack*& s) {
	s = (SqStack*)malloc(sizeof(SqStack));
	s->top = -1;
}
//销毁顺序栈
void DestoryStack(SqStack*& s) {
	free(s);
}
//判断栈是否为空
bool StackEmpty(SqStack* s) {
	return(s->top == -1);
}
//进栈
bool Push(SqStack*& s, Elemtype e) {
	if (s->top == Maxsize - 1)
		return false;
	s->top++;
	s->data[s->top] = e;
	return true;
}
//出栈
bool Pop(SqStack*& s, Elemtype &e) {
	if (s->top == -1)
		return false;
	e = s->data[s->top];
	s->top--;
	return true;
}
//取得栈顶元素
bool Gettop(SqStack*& s, Elemtype &e) {
	if (s->top == -1)
		return false;
	e = s->data[s->top];
	return true;
}
excp3-1.cpp
#include"sqstack.cpp"
int main() {
	Elemtype e;
	SqStack* s;
	cout << "顺序栈的基本运算如下:\n";
	cout << "  (1)初始化栈s\n";
	InitStack(s);
	cout << "  (2)栈为"  << (StackEmpty(s) ? "空" : "非空") << endl;
	cout << "  (3)进栈元素为a,b,c,d,e\n";
	Push(s, 'a');
	Push(s, 'b');
	Push(s, 'c');
	Push(s, 'd');
	Push(s, 'e');
	cout << "  (4)栈为"<<(StackEmpty(s) ? "空" : "非空") << endl;
	cout << "  (5)出栈序列:";
	while (!StackEmpty(s)) {
		Pop(s, e);
		cout << e << " ";
	}
	cout << endl;
	cout << "  (6)栈为"<< (StackEmpty(s) ? "空" : "非空") << endl;
	cout << "  (7)释放栈\n";
	DestoryStack(s);
	return 1;
}

代码思路

实现了顺序栈(一种数据结构)的基本操作,包括初始化、进栈、出栈、判断栈是否为空以及获取栈顶元素等功能,并在 main 函数中对这些功能进行了测试。

  1. InitStack 函数:作用是初始化顺序栈。通过动态分配内存为顺序栈结构体 SqStack 分配空间,并将栈顶指针 top 初始化为 -1,表示栈为空。

  2. DestoryStack 函数:用于销毁顺序栈。释放动态分配给顺序栈的内存空间。

  3. StackEmpty 函数:判断栈是否为空。如果栈顶指针 top 为 -1,则说明栈为空,返回 true;否则返回 false

  4. Push 函数:实现进栈操作。

    • 首先检查栈是否已满,如果栈顶指针等于最大容量减一(s->top == Maxsize - 1),则进栈失败,返回 false
    • 如果栈未满,将栈顶指针加一(s->top++),并将元素 e 存入栈顶位置(s->data[s->top] = e),然后返回 true
  5. Pop 函数:执行出栈操作。

    • 检查栈是否为空,如果栈顶指针为 -1,则出栈失败,返回 false
    • 如果栈非空,将栈顶元素赋值给变量 e,然后将栈顶指针减一(s->top--),并返回 true
  6. Gettop 函数:取得栈顶元素。

    • 检查栈是否为空,如果为空则返回 false
    • 如果栈非空,将栈顶元素赋值给变量 e,并返回 true

实验题2:实现链栈的各种基本运算的算法

题目描述

编写一个程序listack.cpp,实现链栈(假设栈中的元素类型Elemtype为char)的各种基本运算,并在此基础上设计一个程序exp3-2.cpp完成以下功能。

(1)初始化栈s。

(2)判断栈s是否非空。

(3)依次进栈元素a、b、c、d、e。

(4)判断栈s是否非空。

(5)输出出栈序列。

(6)判断栈s是否非空。

(7)释放栈。

listack.cpp程序,其中包含如下函数:

· InitStack(LinkStNode *&s),初始化链找s.

·DestroyStack( LinkStNode *&s): 销毁链栈s.

·StackEmpry(linkStNode s):判断链栈是否为空栈。

·Push(LinkSiNode s &s.ElemType e):元素e进链栈,

· Pop(linkSiNode s &s.ElemType &r): 元素e出链栈。

·Giet TopeLinkStNode &s.ElemType &.e):取链栈的栈顶元素。

运行代码

listack.cpp
#include<iostream>
using namespace std;
#include<stdio.h>
#include<malloc.h>

typedef char Elemtype;

typedef struct Linknode {
    Elemtype data;
    struct Linknode* next;
}LinkStNode;

//初始化链栈
void InitStack(LinkStNode*& s) {
    s = (LinkStNode*)malloc(sizeof(LinkStNode));
    s->next = NULL;
}

//销毁链栈
void DestoryStack(LinkStNode*& s) {
    LinkStNode* p = s;
    while (p != NULL) {
        LinkStNode* temp = p;
        p = p->next;
        free(temp);
    }
}

//判断栈是否为空
bool StackEmpty(LinkStNode* s) {
    return (s->next == NULL);
}

//进栈
void Push(LinkStNode*& s, Elemtype e) {
    LinkStNode* p = (LinkStNode*)malloc(sizeof(LinkStNode));
    p->data = e;
    p->next = s->next;
    s->next = p;
}

//出栈
bool Pop(LinkStNode*& s, Elemtype& e) {
    if (s->next == NULL)
        return false;
    LinkStNode* p = s->next;
    e = p->data;
    s->next = p->next;
    free(p);
    return true;
}

//取得栈顶元素
bool Gettop(LinkStNode* s, Elemtype& e) {
    if (s->next == NULL)
        return false;
    e = s->next->data;
    return true;
}
excp3-2.cpp
#include"listack.cpp"
int main() {
	Elemtype e;
	LinkStNode* s;
	cout << "链栈的基本运算如下:\n";
	cout << "  (1)初始化栈s\n";
	InitStack(s);
	cout << "  (2)栈为"<< (StackEmpty(s) ? "空" : "非空") << endl;
	cout << "  (3)进栈元素为a,b,c,d,e\n";
	Push(s, 'a');
	Push(s, 'b');
	Push(s, 'c');
	Push(s, 'd');
	Push(s, 'e');
	cout << "  (4)栈为"  << (StackEmpty(s) ? "空" : "非空") << endl;
	cout << "  (5)出栈序列:";
	while (!StackEmpty(s)) {
		Pop(s, e);
		cout << e << " ";
	}
	cout << endl;
	cout << "  (6)栈为" << (StackEmpty(s) ? "空" : "非空") << endl;
	cout << "  (7)释放栈\n";
	DestoryStack(s);
	return 1;
}

代码思路

实现了链栈(一种基于链表实现的栈数据结构)的基本操作,包括初始化、进栈、出栈、判断栈是否为空以及获取栈顶元素等功能,并在 main 函数中对这些功能进行了测试。

  1. InitStack 函数:作用是初始化链栈。通过动态分配内存为链栈的头节点 LinkStNode 分配空间,并将头节点的 next 指针初始化为 NULL,表示栈为空。

  2. DestoryStack 函数:用于销毁链栈。遍历链表,依次释放每个节点的内存空间,直到链表为空。

  3. StackEmpty 函数:判断链栈是否为空。如果头节点的 next 指针为 NULL,则说明栈为空,返回 true;否则返回 false

  4. Push 函数:实现进栈操作。

    • 首先动态分配一个新节点 p,将待进栈元素 e 存入新节点的数据域 data
    • 然后将新节点的 next 指针指向当前栈顶节点(即头节点的下一个节点)。
    • 最后将头节点的 next 指针指向新节点,使新节点成为栈顶。
  5. Pop 函数:执行出栈操作。

    • 检查栈是否为空,如果头节点的 next 指针为 NULL,则出栈失败,返回 false
    • 如果栈非空,将栈顶节点(头节点的下一个节点)赋值给临时指针 p,将栈顶节点的数据域 data 赋值给变量 e
    • 然后将头节点的 next 指针指向栈顶节点的下一个节点,即新的栈顶。
    • 最后释放原来的栈顶节点的内存空间,并返回 true
  6. Gettop 函数:取得链栈的栈顶元素。

    • 检查栈是否为空,如果头节点的 next 指针为 NULL,则返回 false
    • 如果栈非空,将栈顶节点(头节点的下一个节点)的数据域 data 赋值给变量 e,并返回 true

顺序栈和链栈的异同点

相同点

  1. 逻辑结构:顺序栈和链栈在逻辑上都遵循后进先出(LIFO - Last In First Out)的原则。这意味着最后进入的数据元素将最先被取出,就像一摞盘子,只能从最上面取放盘子一样。
  2. 基本操作功能:两者都具有基本的操作,如初始化(创建一个空的栈结构)、判断栈是否为空(确定栈中是否有元素)、进栈(将元素压入栈中)、出栈(将栈顶元素弹出)以及获取栈顶元素(查看栈顶元素的值而不弹出它)等操作。这些操作在概念和功能目的上是相同的,只是在具体的实现细节上可能存在差异。

不同点

  1. 存储结构
    • 栈(顺序栈):顺序栈通常使用数组来实现。它在内存中是连续存储的,例如在 C++ 中,可以定义一个数组来存储栈元素,并使用一个变量来表示栈顶指针(指示栈顶元素的位置)。这种存储方式的优点是实现简单、访问速度快,因为数组元素的存储是连续的,可以通过下标直接访问元素。但是,它的缺点是需要预先确定数组的大小,如果栈中元素数量超过数组大小,可能会导致栈溢出;而且在栈的大小变化较大时,可能会造成内存空间的浪费。
    • 链栈:链栈是通过链表实现的,每个节点包含数据域和指向下一个节点的指针域。链栈中的节点在内存中可以不连续存储,通过指针将各个节点连接起来形成栈结构。这种存储方式的优点是可以动态地分配内存,不需要预先确定栈的大小,适合处理元素数量不确定或者变化较大的情况。然而,由于需要额外的指针域来存储节点之间的连接关系,并且访问元素需要通过指针遍历链表,所以在空间和时间效率上相对顺序栈可能会稍低一些。
  2. 空间利用效率
    • 栈(顺序栈):顺序栈在初始化时就分配了固定大小的内存空间,如果栈中元素较少,会造成内存空间的浪费;如果元素数量超过预先分配的空间,则会出现栈溢出的情况。
    • 链栈:链栈的空间是根据实际元素数量动态分配的,每个节点只占用实际需要的内存空间,不会造成大量的空间浪费,但由于每个节点需要额外的指针域,会占用一定的额外空间。
  3. 操作的实现细节
    • 栈(顺序栈):在进栈操作时,需要先检查栈顶指针是否达到数组的最大下标(栈满情况);出栈操作时,需要检查栈顶指针是否为初始值(栈空情况)。并且在顺序栈中,栈顶指针的操作通常是简单的增减下标操作。
    • 链栈:进栈操作需要动态分配新的节点内存,并正确调整指针的指向;出栈操作需要释放节点内存,并重新连接链表指针。在链栈中,操作主要涉及到指针的操作,相对顺序栈来说,指针操作更容易出错,但也更灵活。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

筱姌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值