c++数据结构算法复习基础--6--线性表-栈-常用操作接口-复杂度分析-笔试面试常见问题

特点:先进后出、后进先出

1、顺序栈

依赖数组实现
在这里插入图片描述

代码实现(笔试极其重要,容易让你手写)

**#include<iostream>

using namespace std;

//顺序栈  C++容器适配器 stack  (入栈push 出栈pop 获取栈顶元素top 判断栈空empty 获取栈的元素size)
class SeqStack
{
public:
	SeqStack(int size = 10)
		:mtop(0)
		, mcap(size)
	{
		mpStack = new int[mcap];
	}
	~SeqStack()
	{
		delete[]mpStack;
		mpStack = nullptr;
	}
public:
	//入栈
	void push(int val) 
	{
		if (mtop == mcap)//满了,需要进行栈扩容
		{
			//栈扩容
			expand(2*mcap);
		}
		mpStack[mtop++] = val;
	}
	//出栈
	void pop()
	{
		if (mtop == 0)
			throw "stack is empty";//抛异常
		mtop--;
		return;
	}

	//获取栈顶元素
	int top() const
	{
		if (mtop == 0)
			throw "stack is empty";//抛异常 
		return mpStack[mtop-1];
	}
	//判断是否栈空
	bool empty()const
	{
		return mtop == 0;
	}
	//判断栈元素个数
	int size()const { return mtop; }
private:
	void expand(int size)
	{
		int* p = new int[size];
		memcpy(p,mpStack,mtop*sizeof(int ));
		delete[]mpStack;
		mpStack = p;
		mcap = size;
	}
private:
	int* mpStack;
	int mtop;  //栈顶位置
	int mcap;  //栈空间大小
};**

测试代码

int main()
{
	int arr[] = {5,10,66,77,88,99,100,111};
	SeqStack s;

	for (int v : arr)
	{
		s.push(v);
	}

	while (!s.empty())
	{
		cout << s.top() << " ";
		s.pop();
	}
	cout << endl;
}

运行结果

在这里插入图片描述

2、链式栈

依赖链表实现

代码实现

//顺序栈  C++容器适配器 stack  (入栈push 出栈pop 获取栈顶元素top 判断栈空empty 获取栈的元素size)
class LinkStack
{
public:
	LinkStack():size_(0)
	{
		head_ = new Node;
	}
	~LinkStack()
	{
		Node* p = head_;
		while (p != nullptr)
		{
			head_ = head_->next_;
			delete p;
			p = head_   ;
		}
	}
public:
	//入栈  吧链表头节点后面,第一个有效节点的位置,当作栈顶位置
	void push(int val)
	{
		Node* node = new Node(val);
		node->next_ = head_->next_;
		head_->next_ = node;
		size_++;
	}
	//出栈
	void pop()
	{
		if (head_->next_ == nullptr)
			throw "stack is empty";
		Node* p = head_->next_;
		head_->next_ = p->next_;
		delete p;
		size_--;
	}
	//获取栈顶元素
	int top() const
	{
		if (head_->next_ == nullptr)
			throw "stack is empty";

		return head_->next_->data_;
	}
	//判空
	bool empty()
	{
		return head_->next_ == nullptr;
	}
	//返回栈元素个数  如果遍历一遍链表,记录节点个数为O(n)  想达到O(1)
	int size()const
	{
		return size_;
	}

private:
	struct Node
	{
		Node(int data = 0) :data_(data), next_(nullptr) {}
			int data_;
		Node* next_;
	};

	Node* head_;
	int size_;
};

测试代码

int main()
{
	int arr[] = { 5,10,66,77,88,99,100,111 };
	LinkStack s;

	for (int v : arr)
	{
		s.push(v);
	}

	while (!s.empty())
	{
		cout << s.top() << " ";
		s.pop();
	}
	cout << endl;
}

运行结果

在这里插入图片描述

3、笔试面试常见问题

1)括号匹配问题

思路:

1、便利s串,遇到左括号直接入栈
2、如果遇到右括号,从栈顶取出一个左括号
如果匹配,继续遍历s串中下一个括号
如果不匹配,直接结束掉

代码实现

class Solution {
public:
    bool isValid(string s) {
        stack<char> cs;

        for(char ch:s)
        {
            if(ch == '('||ch=='['||ch=='{')
            {
                cs.push(ch);
            }
            else
            {
                //防止只有右括号
                if(cs.empty())
                    return false;

                //遇到右括号了
                char cmp = cs.top();
                cs.pop();

                if(ch==')' && cmp != '('
                    || ch == ']' && cmp !='['
                    || ch == '}' && cmp !='{')
                    {
                        return false;
                    }
            }
        }

        //栈里面的括号没处理完,防止左括号多
        
        //return true;//err
        return cs.empty();
    }
};

2)逆波兰表达式求解

逆波兰表达式

是一种后缀表达式,所谓后缀就是指算符写在后面。

平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:

去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

思路:

用栈求解四则运算表达式:2+(4+6)/2+6/3
1、中缀表达式 =>逆波兰表达式(后缀表达式)
2、栈计算逆波兰表达式

1、遇到数字直接入栈
2、遇到符号,出栈两个数字
3、运算两个数字,吧结果再入栈
在这里插入图片描述

代码实现

class Solution {
public:
    int calc(int left,int right,char sign)
    {
        switch(sign)
        {
            case '+':
            return left + right;
            case '-':
            return left - right;
            case '*':
            return left * right;
            case '/':
            return left / right;
        }
        throw"";
    }
    
    int evalRPN(vector<string>& tokens) {
        stack<int> intStack;

        for(string &str:tokens)
        {
            if(str.size() == 1 && 
                (str[0] =='+' || str[0]=='-')
                || str[0] == '*' || str[0] == '/')
              {
                //遇到运算符了,开始运算
                int right = intStack.top();
                intStack.pop();

                int left = intStack.top();
                intStack.pop();

                //自定义一个函数判断,进行运算
                intStack.push(calc(left,right,str[0]));
              }
              else
              {
                //遇到数字,直接入数字栈
                //string => int   使用 stoi stol
                //int => string   使用 to_string()
                intStack.push(stoi(str));
              }
        }
        return intStack.top();
    }
};

3)中缀转后缀表达式

理论讲解

遇到数字,直接输出,
遇到符号:
1、栈为空,符号直接入栈
2、如果是‘(’,直接入栈
3、用当前符号和栈顶符号比较其优先级
当前符号优先级 > 栈顶符号 – 当前符号直接入栈,结束
当前符号优先级 < 栈顶符号 – 栈顶符号出栈并输出,继续比较

1、吧栈里面符号都出完了
2、遇到 ‘)’,要一直出栈,直到遇见 ‘(’ 为止

代码实现

#include<iostream>
#include<string>
#include<stack>

using namespace std;

//比较符号有限级
bool  Priority(char ch, char topch)
{
	if ((ch == '*' || ch == '/') && (topch == '+' || topch == '-'))
		return true;
	if (ch == ')')
		return false;
	if (topch == '(' && ch != ')')
		return true;

	//if (ch == ')')
	//	return false;
	return false;
}

//中缀表达式  => 后缀表达式
//这里默认都为正整数
string MiddleToEndExpr(string expr)
{
	string result;
	stack<char> s;

	for (char ch : expr)
	{
		if (ch >= '0' && ch <= '9')
		{
			result.push_back(ch);
		}
		else
		{
			for(;;)
			{
				//处理符号
				if (s.empty() || ch == '(')
				{
					s.push(ch);
					break;
				}

					//比较当前符号和栈顶符号的优先级
					char topch = s.top();

					//计算优先级
					//Priority:true  ch > topch    fales ch <= topch
				if (Priority(ch, topch))
				{
					s.push(ch);
					break;
				}
				else
				{
					s.pop();
					if (topch == '(') // 如果遇见')',一直出栈,直到遇见'('
						break;
					result.push_back(topch);
				}
				
			}
		}
	}

	//如果符号栈还存留符号,直接输出到后缀表达式里面
	while (!s.empty())
	{
		result.push_back(s.top());
		s.pop();
	}

	return result;
}

代码测试

int main()
{
	cout << MiddleToEndExpr("(1+2)*(3+4)") << endl;
	cout << MiddleToEndExpr("2+(4+6)/2+6/3") << endl;
	cout << MiddleToEndExpr("2+6/(4-2)+(4+6)/2") << endl;
	cout << MiddleToEndExpr("") << endl;
}

运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值