自己学习整理的笔记,给自己温故而知新。
表是动态的数据结构,大小可以改变。
数组是静态的数据结构,在程序编译的时候它的大小是固定的。
栈是一种形式的表。是LIFO后进先出的。
此时用到的栈是C++STL标准库当中的,我们可以拿来用,但是不知道里面具体内容,这就是信息隐藏的一种。
(1)反转表
#include
#include
using namespace std;
int main(){
/*Pre:The user supplies an integer n and n decimal numbers 前置条件
Post:The number are printed in reverse order 后置条件
Uses:The STL class stack and its methods*/ //使用方法
int n;
double item;
stack<double> numbers;
cout<<"Type in an integer n followed by n decimal numbers."<<endl
<<"The numbers will be printed in reverse order."<<endl;
cin>>n;
for(int i=0;i<n;i++){
cin>>item;
numbers.push(item);
}
cout<<endl;
while(!numbers.empty()){
cout<<numbers.top()<<" ";
numbers.pop();
}
cout<<endl;
}
(2)字符串反转
#include
#include
using namespace std;
int main(){
/*Pre:The user supplies an string 前置条件
Post:The string are printed in reverse order 后置条件
Uses:The STL class stack and its methods*/ //使用方法
char input;
stack<char> text;
cout<<"Type in an string."<<endl
<<"The string will be printed in reverse order."<<endl;
while((input=cin.get())!='\n'){
text.push(input);
}
while(!text.empty()){
cout<<text.top();
text.pop();
}
cout<<endl;
}
(3)整数条件反转
#include
#include
using namespace std;
int main(){
/* Pre: An increasing sequence of integers is entered, input is terminated by a final integer that
is smaller than its predecessor.
Post: The sequence is printed in decreasing order. */
int input;
stack<int> numbers;
cout<<"Type in an integer n followed by n int numbers."<<endl
<<"The numbers will be printed in reverse order."<<endl;
cin>>input;
numbers.push(input);
while(1){
cin>>input;
if(input>numbers.top()){
numbers.push(input);
}
else
break;
}
while(!numbers.empty()){
cout<<numbers.top()<<" ";
numbers.pop();
}
cout<<endl;
}
1.进栈顺序为abcde,有哪些合法的出栈顺序?
这里引入一个概念,叫卡特兰(Catalan)数。
n个不同元素进栈,出栈元素不同排列的个数为
这就是卡特兰数。
记忆方法:10个元素进栈,n=10,2n=20,n+1=11,故卡特兰数为:
20 * 19 * 18 *… * 11
——————————
11 * 10 * … * 1
若要说写出具体的出栈顺序,只能枚举了,可以通过卡特兰数防止少写。
C++STL中有几种栈的实现,作为新手,用用STL倒无可厚非,但是当实际遇到项目时,程序某些功能可能与这些栈不相匹配,导致程序性能不能进一步被开发,故还得自己设计和改进。
必须包括empty()、top()、push()、pop()的基本操作以及空栈的初始化。
1.构造函数
2.元素类型与泛型
我们用Stack_entry作为Stack栈中的类型,它可以是int,也可以是char。
typedef char Stack_entry;
对于不同的元素类型使用同样的基本数据结构和操作的能力称为泛型(generic)。
3.错误处理
使用单一的称为Error_code的枚举类型来报告所有来自于程序和函数的错误。
//类定义一般放在stack.h中
//相对应的代码文件称为stack.c
const int maxstack = 10;
class Stack{
public:
Stack();
bool empty() const;
Error_code pop();
Error_code top(Stack_entry &item) const;
Error_code push(const Stack_entry &item);
private:
int count;
Stack_entry entry[maxstack];
};
#include
Error_code Stack::push(const Stack_entry &item)
/* Pre: None.
Post: If the Stack is not full, item is added to the top of the Stack. If the Stack
is full, an Error_code of overflow is returned and the Stack is left unchanged. */
{
Error_code outcome=success;
if(count>=maxstack)
outcome=overflow;
else
entry[count++]=item;
return outcome;
}
Error_code Stack :: pop( )
/* Pre: None.
Post: If the Stack is not empty, the top of the Stack is removed. If the Stack is
empty, an Error_code of underflow is returned. */
{
Error_code outcome = success;
if (count == 0)
outcome = underflow;
else --count;
return outcome;
}
Error_code Stack ::top(Stack_entry &item) const
/* Pre: None.
Post: If the Stack is not empty, the top of the Stack is returned in item. If the
Stack is empty an Error_code of underflow is returned. */
{
Error_code outcome = success;
if (count == 0)
outcome = underflow;
else
item = entry[count - 1];
return outcome;
}
bool Stack :: empty( ) const
/* Pre: None.
Post: If the Stack is empty, true is returned. Otherwise false is returned. */
{
bool outcome = true;
if (count > 0) outcome = false;
return outcome;
}
Stack :: Stack( )
/* Pre: None.
Post: The stack is initialized to be empty. */
{
count = 0;
}
只有pop、push、top三个方法的数据类型是Error_code,因为就这三个可能会出现错误和异常。
Error_code copy_stack(Stack &dest, Stack &source)
/* Pre: None.
Post: Stack dest has become an exact copy of Stack source; source is unchanged. If an error is
detected, an appropriate code is returned; otherwise, a code of success is returned. */
{
dest = source;
return success;
}
Error_code copy_stack(Stack &dest, Stack &source)
/* Pre: None.
Post: Stack dest has become an exact copy of Stack source; source is unchanged. If an error is
detected, an appropriate code is returned; otherwise, a code of success is returned. */
{
Error_code detected = success;
Stack temp;
Stack_entry item;
while (detected == success && !source.empty( )) {
detected = source.top(item);
detected = source.pop( );
if (detected == success) detected = temp.push(item);
}
while (detected == success && !temp.empty( )) {
detected = temp.top(item);
detected = temp.pop( );
if (detected == success) detected = source.push(item);
if (detected == success) detected = dest.push(item);
}
return detected;
}
Error_code copy_stack(Stack &dest, Stack &source)
/* Pre: None.
Post: Stack dest has become an exact copy of Stack source; source is unchanged. If an error is
detected, an appropriate code is returned; otherwise, a code of success is returned. */
{
dest.count = source.count;
for (int i = 0; i < source.count; i++)
dest.entry[i] = source.entry[i];
return success;
}
第一个版本当然是最容易编写的,如果堆栈几乎满了,它将运行得最快,因为编译器将生成机器代码比第三个方法的循环更快地复制所有条目。但是,如果堆栈更接近空,那么第三个方法将是最快的,因为它只复制占用的条目,而第一个方法复制数组中的所有位置,无论是否占用。由于所有函数调用,第二个版本可能运行最慢,但如果堆栈几乎为空,它可能会超过第一个版本。
当栈满的时候,都是要复制所有条目,编译器生成机器代码进行复制是最接近底层的,最快的。但是若栈更接近于空的时候,编译器生成机器代码还是一股脑的全复制,所以还是第三个方法快。
第二个版本独立于实现,因此,如果实现可能发生更改,则最好使用第二个版本。第一种方法将在链接实现中失败,因为它只会将变量source和dest设置为指向同一节点。因此,第一种方法不会制作新的堆栈副本;source和dest成为同一个堆栈,更改其中一个将更改另一个。