数据结构 - 第三章 栈

数据结构 - 第三章 栈

一、铁路进行列车调度时常把站台设计成栈式结构的站台,试问:

(1)出栈序列

需求:设有编号为 1,2,3,4,5, 6 的 6 辆列车,顺序开入栈式 结构的站台,则可能的出栈序列有多少种?
在这里插入图片描述

(2)判断是否可以进栈

需求:若进站的 6 辆列车顺序如上所述,那么是否能够得到 435612,325641,154623 和 135426 的出站序列,如果不能,说明为什么不能;如果能,说明如何得到(即写出“进栈”或“出栈”的 序列)

注意这里的进栈顺组必须是按照1 2 3 4 5 的顺序
325641:(可行)

执行顺序 栈内元素 出栈序列
1,2,3先进栈 1 2 3 -
3出栈 1 2 3
2出栈 1 3 2
4,5进栈 1 4 5 3 2
5出栈 1 4 3 2 5
6进栈 1 4 6 3 2 5
全部出栈 - 3 2 5 6 4 1

135426:(可行)

执行顺序 栈内元素 出栈序列
1进栈 1 -
1出栈 - 1
2 3进栈 2 3 1
3出栈 2 1 3
4 5进栈 2 4 5 1 3
5出栈 2 4 1 3 5
4出栈 2 1 3 5 4
6进栈 2 6 1 3 5 4
全部出栈 - 1 3 5 4 6 2

435612:这样的出栈序列,说明4356出完栈之后才是1和2,那么1和2就一直在栈中,而且1要在2之前出栈,但是根据题目顺序进栈,1在2的前面进栈,那么就只能2先出栈

154623:2 3和上面的情况类似,只能是3 2的出栈顺序

二、写出下列中缀表达式的后缀表达式

中缀表达式 后缀表达式
ABC ABC * * 或者 ABC
-A+B-C+D A-B+C-D+
A*-B+C A*B-C+
(A+B)* D+E/(F+A*D)+C AB+D * EFAD*+/+C+
A&&B || !(E>F) {注:按照C++的优先级} AB && EF>! ||
!(A && ! ((B < C) || (C > D)) ) || (C < E) ABC< CD> || ! &&! CE< ||

三、借助栈实现单链表上的逆置运算

template <class T>
struct LinkNode {
    
    
	T data;
	LinkNode<T>* next;

	LinkNode(LinkNode<T>* ptr = NULL) :next(ptr) {
    
    }
	//这里不能有分号
	//还需要加入大括号
	LinkNode(const T& item, LinkNode<T>* ptr = NULL) :data(item), next(ptr) {
    
    }
};


template<class T>
bool LinkStack<T>::reverseList(LinkList<T>& list)
{
    
    
	//先使用栈获取链表的每个元素
	LinkStack<T> s1;
	LinkNode<T>* p = NULL;
	

	if (!list.first->next) {
    
    
		cerr << "链表不可逆转" << endl;
		exit(1);
	}
	p = list.first->next;

	while (p) {
    
    
		s1.push(p->data);
		LinkNode<T>* q = p;//暂时存储需要删除的结点
		p = p->next;
		list.first->next = p;
		delete q;
	}
	
 
	/*list.first->next = s1.top;*/
	//s1会被释放,局部变量,所以上面只是将头结点链接之后还是会释放

	LinkNode<T>* s = list.first;
	while (s) {
    
    
		
		s->next = new LinkNode<T>(s1.top->data);
		s1.pop();
		s = s->next;
		if (!s1.top)break;
		//注意,这里还不能判断s,因为s无论何时,next都为空值,如果在while判断的时候加
		//s->next,那么不会进入,如果在末尾加s->next ,那么循环执行一次就结束
	}

	return true;
	
}

//测试逆转函数
/*
{
	LinkList<int> list;
	for (int i = 0; i < 10; i++) {
		LinkNode<int>* node = new LinkNode<int>(rand() % 13);//使用后插法构建一个链表
		list.ListInsert_back(node);
	}
	cout << "链表逆转前:";
	list.ListPrint();
	LinkStack<int>::reverseList(list);
	cout << "链表逆转后:";
	list.ListPrint();
	/*
	输出结果:
	链表逆转前:2       7       3       6       7       7       12      4       0       11
    链表逆转后:11      0       4       12      7       7       6       3       7       2
}
*/

四、双栈的实现

需求:将编号为0 和1 的两个栈存放于一个数组空间 V[m]中,栈底分别处于数组的 两端。当第 0 号栈的栈顶指针 top[0]等于-1 时该栈为空,当第 1 号栈的栈顶指针 top[1] 等于 m 时该栈为空。两个栈均从两端向中间增长。当向第 0 号栈插入一个新元素时,使 top[0]增 1 得到新的栈顶位置,当向第 1 号栈插人一个新元素时,使 top[1]减 1 得到新的栈 顶位置。当 top[0]+1 == top[1]时或 top[0]= top[1]-1 时,栈空间满,此时不能再向 任一栈加入新的元素。试定义这种双栈结构的类定义,并实现判栈空、判栈满、插人、删除 算法

//DoubleStack.h

template <class T>
class DoubleStack {
    
    

public:
	DoubleStack(int size = 20);
	~DoubleStack();

	bool push(T x,int i);
	bool pop(int i);
	bool isEmpty(int i);  //判断是那个栈是空的
	bool isFull()const {
    
     return top[0] + 1 == top[1]; }
	void makeEmpty(int i);

private:
	int top[2], bot[2];//两个栈顶指针,栈底指针
	T* elem;
	int maxSize;

};

//DoubleStack.hpp
#include <assert.h>
#include "DoubleStack.h"

template<class T>
DoubleStack<T>::DoubleStack(int size) {
    
    
	elem = new T[size];
	assert(elem != NULL);

	maxSize = size;
	top[0] = bot[0] = -1;
	top[1] = bot[1] = size;

}

template<class T>
DoubleStack<T>::~DoubleStack()
{
    
    
	delete[]elem;
}

template<class T>
inline bool DoubleStack<T>::push(T x, int i)
{
    
    
	if (isFull())return false;

	if (!i)elem[++top[0]] = x;
	else elem[--top[1]] = x;
	return true;

}

template<class T>
inline bool DoubleStack<T>::pop(int i)
{
    
    
	if (isEmpty(i)) return false;

	if (!i)elem[--top[0]];
	else elem[--top[1]];
	return true;
}

template<class T>
inline bool DoubleStack<T>::isEmpty(int i)
{
    
    
	return top[i] = bot[i];
}

template<class T>
void DoubleStack<T>::makeEmpty(int i)
{
    
    
	if (!i)top[0] = bot[0] = -1;
	else top[1] = bot[1] = maxSize;
}


五、括号匹配

需求:试着编写一个算法,检查一个程序中的花括号,方括号,圆括号是否配对,如果能配对就返回真,否则返回假

说明:这里没有完全按照题目的需求

template<class T>
void LinkStack<T>::bracketMatch(const char* expression)
{
    
    
	int size = 20;
	int j = 0;
	int length = strlen(expression);

	LinkStack<int> s1,//小括号
		s2, //中括号
		s3; //大括号

	for (int i = 0; i < length; i++) {
    
    
		if (expression[i] == '(')s1.push(i + 1);
		else if (expression[i] == ')') {
    
    
			if (s1.pop(j))cout << i+1 << "与" << j << "匹配( )" << endl;
			else cout << "没有与第" << i+1 << "个右小括号的左小括号" << endl;
		}

		if (expression[i] == '[')s2.push(i + 1);
		else if (expression[i] == ']') {
    
    
			if (s2.pop(j))cout << i+1 << "与" << j << "匹配[ ]" << endl;
			else cout << "没有与第" << i+1 << "个右中括号的左中括号" << endl;
		}


		if (expression[i] == '{')s3.push(i + 1);
		else if (expression[i] == '}') {
    
    
			if (s3.pop(j))cout << i+1 << "与" << j << "匹配{ }" << endl;
			else cout << "没有与第" << i+1 << "个右大括号的左大括号" << endl;
		}

	}
	
	while (!s1.isEmpty()) {
    
    
		s1.pop(j);
		cout << "没有与第" << j << "个左小括号匹配的右小括号" << endl;
		
	}

	while (!s2.isEmpty()) {
    
    
		s2.pop(j);
		cout << "没有与第" << j << "个左中括号匹配的右中括号" << endl;
		
	}


	while (!s3.isEmpty()) {
    
    
		s3.pop(j);
		cout << "没有与第" << j << "个左大括号匹配的右大括号" << endl;
		
	}

	
}

//测试括号匹配函数
/*
{
	LinkStack<int>::bracketMatch("99()[[[[]{
    
    {}");
	/*
	输出结果:
	4与3匹配( )
    9与8匹配[ ]
    12与11匹配{ }
    没有与第7个左中括号匹配的右中括号
    没有与第6个左中括号匹配的右中括号
    没有与第5个左中括号匹配的右中括号
    没有与第10个左大括号匹配的右大括号
}
*/

六、递归算法

需求:已知f为单链表的表头指针,链表中储存的都是整形的数据,写出实现下面算法的递归算法

(1)求链表中的最大整数

template<class T>
T LinkList<T>::SearchMax_Recursion(LinkNode<T>* node) 
{
    
    
	if (!node) return 0;
	if (!node->next) return node->data;
	
	int max = SearchMax_Recursion(node->next);
	/*
	这里递归算法的实现大概是:
	这里的函数会一直执行到最后一个节点,那么满足第二个if条件,返回的data才是max的初始值
	,这时的max和上一个节点的数值进行比较,返回其中的最大值再次和上一个节点的数值进行比较
	如此往复,最后返回最终的最大值

	前面的两个if条件语句是防止进入死循环
	*/
	return (max > node->data) ? max : node->data;
}

//递归调用之获取最大值
/*
{
	LinkList<int> list;
	for (int i = 0; i < 10; i++) {
		LinkNode<int>* node = new LinkNode<int>(rand() % 13);//使用后插法构建一个链表
		list.ListInsert_back(node);
	}
	list.ListPrint();
	cout << "链表的最大值是:" << LinkList<int>::SearchMax_Recursion(list.first) << endl;
	/*
	输出结果:
	2       7       3       6       7       7       12      4       0       11
    链表的最大值是:12
}	
*/

(2)求链表的结点个数

template<class T>
inline T LinkList<T>::Number_Recursion(LinkNode<T>* node)
{
    
    
	static int k = 0;
	if (!node->next)return 1;//目的只是作为递归调用结束的条件

	Number_Recursion(node->next);
	k++;
	return k;

}

//递归调用之获取节点数
/*
{
	LinkList<int> list;
	for (int i = 0; i < 10; i++) {
		LinkNode<int>* node = new LinkNode<int>(rand() % 13);//使用后插法构建一个链表
		list.ListInsert_back(node);
	}

	list.ListPrint();
	cout << "该链表的节点个数是:" << LinkList<int>::Number_Recursion(list.first) << endl;
	/*
	输出结果:
	2       7       3       6       7       7       12      4       0       11
    该链表的节点个数是:10
}
*/

(3)求所有整数的平均值

template<class T>
inline float LinkList<T>::Average_Recursion(LinkNode<T>* node)
{
    
    
	/*static int ave = 0;
	static int n = 0;

	if (!node->next) {
		return node->data;
		
	}
	Average_Recursion(node->next);
	ave = (ave + node->next->data);
	
	return ave;
	求总和
	*/
	//以1,2,3为例,计算次序为3;(3*1+2)/2=2.5;(2.5*2+1)/3=2;

	static int n = 0;
	if (!node->next) {
    
    
		n = 0;
		return 0;
	}
	
	float m = Average_Recursion(node->next);//m必须是float型
    n++;
	return (float)((n - 1) * m + node->next->data) / n;

}

//递归调用之获取节点数据的平均值
/*
{
	LinkList<int> list(0);
	
	for (int i = 0; i < 10; i++) {
		LinkNode<int>* node = new LinkNode<int>(rand() % 13);//使用后插法构建一个链表
		list.ListInsert_back(node);
	}

	list.ListPrint();
	cout << "链表的平均值是:"<< LinkList<int>::Average_Recursion(list.first) << endl;
	/*
	2       7       3       6       7       7       12      4       0       11
    链表的平均值是:5.9
}
*/

猜你喜欢

转载自blog.csdn.net/qq_51672565/article/details/117392059