1.栈
栈是一个线性表,如下图,其特点是后进先出。对栈来说,表尾部是栈顶,表头是栈底,不含元素的栈叫空栈。栈的基本操作除了出栈、入栈,还有初始化栈,空栈判断、取栈顶元素等。
(1)顺序栈
利用顺序方式存储的栈为顺序栈,栈许多操作在栈顶实现,因此需要设置一个栈顶指示器标注栈顶位置。栈的应该包括连续空间首地址、顺序栈的最大空间和栈中元素的个数。
(1)进栈操作:在栈未满的情况下,允许元素进栈,栈顶指示器往上移一个空间,然后将一个新元素放进栈中。(2)出栈操作:将栈顶指示器所指的值保存在一个变量中,再将栈顶指示器向下移动。(3)取栈:将栈顶指示器所指值保存至一个变量中
(2)共享栈
为了防止顺序栈溢出,通常需要给栈分配较大空间,但如果栈中没有几个元素,又会造成空间浪费。当需要使用同类型栈时,为了充分利用各个栈的空间,采用多个栈共享存储。
假设共享栈中的两个栈共享一个连续的存储空间,栈底设在大栈的两端,往中间入栈。
(1)入栈操作:两个栈均从两顿往中间入栈,直到栈满。
(3)链栈
是指用链式存储结构实现的栈。与单向链表相似,但没有头结点。
2.递归
递归在程序中执行效率极低。
对于递归问题,可以转换为非递归解决。
(1)直接转换法
该方法常用来消除尾递归和单向递归,用循环或迭代代替递归!
例如下面的求阶乘的代码:
#include <iostream>
#include <Windows.h>
long factorial1(int n)
{
int temp = n;
if (n == 0)
{
temp = 1;
return temp;
}
else
{
temp = temp * factorial1(temp-1);
return temp;
}
}
long factorial2(int n)
{
int temp = n;
int ans = n;
for (int i = 1; i <n; i++)
{
temp--;
ans = ans * temp;
}
return ans;
}
void main()
{
int n;
long ans1,ans2;
std::cin >> n;
std::cout << std::endl;
DWORD start_time1 = GetTickCount();
for (int i = 0; i < 80000; i++)
{
ans1 = factorial1(n);
}
DWORD end_time1 = GetTickCount();
DWORD start_time2 = GetTickCount();
for (int i = 0; i < 80000; i++)
{
ans2 = factorial2(n);
}
DWORD end_time2 = GetTickCount();
std::cout << ans1 <<" "<< (end_time1 - start_time1) <<"ms"<< std::endl;
std::cout << ans2 << " " << (end_time2 - start_time2) << "ms" << std::endl;
}
其输出如下图:
明显可以看出尾递归的速度明显慢于循环……
(2)间接转化法
利用栈保存中间结果,根据递归函数在栈中的变化结果得到答案。