【数据结构与算法】【C++】链栈实验报告(三)

目录

阅读建议:

一、实验目的

二、实验内容

三、实验过程

四、代码结构

五、测试结果


阅读建议:

1.实验的软硬件环境要求:

(1)硬件环境要求:PC机
(2)软件环境要求:Windows 环境下的 Microsoft Visual Studio

2.该实验采用了头文件(.h)和源文件(.cpp)相结合的形式。


一、实验目的

1.熟练掌握栈的链式存储结构的实现;

2.熟练掌握链栈的基本操作算法实现,包括建栈、入栈、出栈、读栈顶元素和释放栈等;

3.灵活使用栈来解决具体的问题。


二、实验内容

1.定义链栈类,封装链栈的基本操作算法;(建议将链栈的类模板及实现算法单独写入.h头文件中);

2.利用链栈的基本操作与特性,从以下题目中选择一个完成:

(1)十进制数转换为二、八、十六进制数

(2)算术表达式的括号匹配合法性判断(表达式中包括的括号类型有圆括号()、方括号[]以及花括号{})

(3)简单算术表达式求值。(表达式里包含运算数、+、-、*、/四类运算符及小括号())


三、实验过程

1.结点结构

template <typename T>
struct Node
{
	T data;  //数据域
	Node<T>* next;  //指针域
};

2.构造函数,初始化一个空的链栈。

工作原理:在链栈中,top通常表示栈顶元素,而这里将其初始化为NULL,意味着一开始这个链栈是空的,没有栈顶元素。

template<typename T>
LinkStack<T>::LinkStack() 
{
	top = NULL;  //初始化栈顶指针为空  
}

3.析构函数,删除LinkStack<T>对象时,自动清理其占用的内存资源。

工作原理:代码遍历了链栈中的所有节点,并释放了它们所占用的内存。这是通过一个循环实现的,循环条件是top != NULL,即只要栈顶指针不为空,就继续循环。在循环中,首先将当前栈顶指针赋值给p,然后将top指向下一个节点,接着删除p指向的节点。这样,所有的节点都会被遍历并释放,从而确保链栈所占用的内存被正确地释放。

template<typename T>
LinkStack<T>::~LinkStack() 
{
	Node<T>* p = NULL;
	while (top != NULL) {
		p = top;
		top = top->next;
		delete p;
	}
}

4.入栈操作,将一个元素压入链栈的栈顶。

工作原理:首先创建一个新的节点指针p并初始化为NULL。然后通过new操作符动态分配内存,并将新节点的指针赋值给p。接着,将元素x赋值给新节点的数据域,并将新节点的next指针指向当前的栈顶元素(即top)。最后,更新栈顶指针top,使其指向新节点,完成压栈操作。

template<typename T>
void LinkStack<T>::Push(T x)
{
	Node<T>* p = NULL;
	p = new Node<T>;
	p->data = x;
	p->next = top;
	top = p;  //将p插在栈顶
}

5.出栈操作,从链栈的栈顶弹出元素,并返回其值。

工作原理:首先创建一个新的节点指针p并初始化为NULL,以及一个变量x用于存储弹出元素的值。然后,通过一个if语句检查栈是否为空。如果栈为空(即栈顶指针topNULL),则抛出一个异常,表示下溢。

如果栈不为空,则将栈顶节点的数据域赋值给变量x,并将栈顶指针top暂存到指针变量p中。接着,将栈顶指针top更新为下一个节点,即将栈顶节点从链表中摘除。最后,释放暂存的栈顶节点的内存,并返回弹出元素的值。

template<typename T>
T LinkStack<T>::Pop()
{
	Node<T>* p = NULL;
	T x;
	if (top == NULL) {
		throw "下溢";
	}
	x = top->data;
	p = top;  //暂存栈顶元素
	top = top->next;  //将栈顶节点摘除
	delete p;
	return x;
}

6.读栈顶元素,获取链栈的栈顶元素的值,如果链栈为空则返回-1。

工作原理:首先通过一个if语句检查链栈是否为空。如果链栈为空(即栈顶指针topNULL),则输出一个错误信息并返回-1。

如果链栈不为空,则直接返回栈顶节点的数据域的值。

template<typename T>
T LinkStack<T>::GetTop()
{
	if (Empty()) {
		cout << "栈链为空!" << endl;
		return -1;
	}
	return top->data;
}

7.判断链栈是否为空。

工作原理:函数返回一个布尔值,如果链栈的栈顶指针topNULL,即链栈为空,则返回true;否则返回false

template<typename T>
bool LinkStack<T>::Empty()
{
	return top == NULL;
}

8.检查括号是否匹配。

工作原理:函数接受两个字符参数lr,分别表示左括号和右括号。函数通过一个if语句判断左括号和右括号是否匹配,如果匹配则返回true,否则返回false

template<typename T>
bool LinkStack<T>::isPaired(char l, char r) 
{
	if ((l == '(' && r == ')') || (l == '[' && r == ']') || (l == '{' && r == '}'))
		return true;
	else
		return false;
}

9.检查表达式的括号是否匹配。

工作原理:函数接受一个字符串参数expr,表示待判断的表达式。函数首先创建一个空的链栈s,然后遍历表达式中的每个字符。对于每个左括号(即([{),将其压入栈中;对于每个右括号(即)]}),首先检查栈是否为空。如果栈为空,则表达式不合法,返回false。如果栈不为空,但当前右括号与栈顶的左括号不匹配,则表达式不合法,返回false

在遍历完表达式中的所有括号后,继续检查栈中是否还有剩余的左括号。如果有,则将栈中的每个左括号与一个虚拟的右括号(用NULL表示)进行匹配检查。如果某个左括号与虚拟的右括号不匹配,则表达式不合法,返回false;如果表达式中的所有括号都匹配合法,则返回true

template<typename T>
bool LinkStack<T>::ParenthesesMatch(string expr)
{
	LinkStack<T> s;
	for (char c : expr) {
		if (c == '(' || c == '[' || c == '{') {
			s.Push(c);
		}
		else if (c == ')' || c == ']' || c == '}') {
			if (s.Empty()==true) {
				return false;
			}
			else if (isPaired(s.Pop(), c)==false) {
				return false;
			}
		}
	}
	while (!s.Empty()) {
		if (isPaired(s.Pop(), NULL) == false) {
			return false;
		}
	}
	return true;
}

10.主函数

int main()
{
    int x;
    LinkStack<int>S{};  //定义链栈变量S
    LinkStack<int>E{};  //定义链栈变量E
    /*cout << "入栈元素:15、5";
    S.Push(15);
    S.Push(5);
    cout << endl << "当前栈顶元素:" << S.GetTop() << endl;
    try {
        x = S.Pop();
        cout << "出栈元素:" << x << endl;
    }
    catch (char* str) {
        cout << str << endl;
    }
    cout << "当前栈顶元素:" << S.GetTop() << endl;
    try {
        cout << "请输入待插入元素:";
        cin >> x;
        S.Push(x);
    }
    catch (char* str) {
        cout << str << endl;
    }
    cout << "当前栈顶元素:" << S.GetTop() << endl;
    if (S.Empty() == true) {
        cout << "栈为空" << endl;
    }
    else
    {
        cout << "栈非空" << endl;
    }

    try {
        x = S.Pop();
        cout << "出栈元素:" << x << endl;
    }
    catch (char* str) {
        cout << str << endl;
    }
    try {
        x = S.Pop();
        cout << "出栈元素:" << x << endl;
    }
    catch (char* str) {
        cout << str << endl;
    }
    cout << "当前栈顶元素:" << S.GetTop() << endl;*/

    string expr;
    cout << "输入表达式: ";
    getline(cin, expr);
    if (E.ParenthesesMatch(expr)) {
        cout << "表达式中的括号匹配。" << endl;
    }
    else {
        cout << "表达式中的括号不匹配。" << endl;
    }

    return 0;
}

四、代码结构


五、测试结果

1.基本操作

2.算术表达式的括号匹配合法性判断


        完整代码链接:https://download.csdn.net/download/weixin_73286497/88758690

        希望大家可以在该篇实验报告中有所收获,同时也感谢各位大佬的支持。文章如有任何问题请在评论区留言斧正,鸿蒙会尽快回复您的建议!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鸿·蒙

您的赞赏是我进步的燃料,感谢您

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

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

打赏作者

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

抵扣说明:

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

余额充值