1. 栈介绍:
栈是限定仅在表尾进行插入或者删除操作的线性表。因此,对于栈而言,表尾端有其特殊意义,成为栈顶(top),表头端称为栈底。栈又称为后进先出的顺序表。
2.栈的功能介绍:
栈的功能函数有:插入,删除,获取栈顶元素,获取长度,判断栈是否为空。
(1) 栈的基本定义代码如下:
template<typename Type>
class Stack
{
private:
Type *data;
int length;
int MAX;
public:
Stack();
~Stack();
Type top();
bool pop();
bool empty();
void push(Type data);
void clear();
int size();
};
(2) 插入
函数原型:void push(Type data)
介绍:插入时,首先需要判断一下栈是否已经满了,满了的话重新分配空间。分配空间的原则和模板类vector一样,以原来的两倍为新的空间,然后将数据重新复制过去,复杂度为栈的长度。没有满的时候直接插入。
template<typename Type>
void Stack<Type>::push(Type number)
{
if(this->length == this->MAX)
{
Type* data = new Type[this->length*2];
for(int i=0;i<this->length;i++)
{
data[i] = this->data[i];
}
data[this->length] = number;
if(this->data != NULL)delete[] this->data;
this->data = data;
this->length = this->length+1;
this->MAX = this->MAX*2;
}
else
{
this->data[this->length++] = number;
}
}
(3) 删除
函数原型:bool pop()
介绍:删除比较简单,只需要将length-1就好了。如果栈中没有元素,返回false,否则,删除后返回true。
template<typename Type>
bool Stack<Type>::pop()
{
if(this->length == 0) return false;
else
{
length--;
return true;
}
}
(4) 其他比较简单,读者可以自行完成。
3.栈的应用
(1) 进制的变换
(我的例子是以十进制为输入,以mod进制返回,读者可以自己写个m进制转n进制的。思路也差不多,先把m进制转成10进制,然后再进行一下变化。此外,我的代码不支持32位以上的,如果有需要,可以自行写个高精度进制转换。)
进制的转换无非就是存余数,算出商,存余数,算出商......举个简单的例子,11(10)转成x(2),问x等于几。
N | N/2 | N%2 |
11 | 5 | 1 |
5 | 2 | 1 |
2 | 1 | 0 |
1 | 0 | 1 |
那么11(10)=1011(2)
int Change(int Num,int mod)
{
Stack<int> stack = Stack<int>();
while(Num)
{
stack.push(Num%mod);
Num = Num/mod;
}
int afterNum = 0;
while(!stack.empty())
{
afterNum = afterNum * 10 + stack.top();
stack.pop();
}
return afterNum;
}
(2) 括号匹配
括号匹配也很简单,先判断是否为'('/'[',是,则直接插入栈,否则,如果不是这两种组合('('和')')/('['和']')则返回false。直到列表扫描完毕,如果此时栈不为空,则返回false,否则,返回true。
bool isOk(char *str)
{
Stack<char> stack = Stack<char>();
int len = strlen(str);
for(int i=0;i<len;i++)
{
if(str[i] == '(' || str[i] == '[')
stack.push(str[i]);
else
{
if(stack.size() == 0) return false;
if(str[i] == ')' && stack.top() != '(') return false;
if(str[i] == ']' && stack.top() != '[') return false;
stack.pop();
}
}
if(stack.size() == 0) return true;
else return false;
}
(3) 行编辑程序。
觉得这个没什么好讲的。觉得那个输出比较适合用队列做,不过删除一个元素和一行元素比较适合用栈做,都可以吧。
void LinkEdit(char *ch)
{
Stack<char> stack = Stack<char>();
int len = strlen(ch);
for(int i=0;i<len;i++)
{
while(i < len && ch[i] != '\n')
{
switch(ch[i])
{
case '#':
if(!stack.empty()) stack.pop();
break;
case '@':
stack.clear();
break;
default:
stack.push(ch[i]);
}
i++;
}
char *str = new char[stack.size() + 1];
int num = 0;
while(!stack.empty())
{
str[num++] = stack.top();
stack.pop();
}
str[num] = '\0';
for(int j=0;j<num/2;j++)
swap(str[j],str[num-j-1]);
printf("%s\n",str);
delete[] str;
stack.clear();
}
}
(4) 迷宫求解问题
(5) 表达式求值
*以上两个我还在做总结,等做完之后在一起整理出来。迷宫求解问题也可以用队列做。迷宫求解问题也可以推广到扫雷雷生成问题,思路是一样的。此外,除了这些例子,面试中最常见的还是给你入栈顺序,问你一下那个出栈顺序是不满足的。