栈的应用
引例 :函数调用背后的过程
void func1(int a, int b) {
int x;
func2(x);
x = x + 10086;
}
void func2(int x) {
int m, n;
}
int main(){
int a,b,c;
func1(a, b);
c = a + b;
}
函数调用的特点:最后被调用的函数最先执行结束。
当程序在运行的时候,系统会为我们在内存中开辟一块空间,作为函数调用栈
(1)以main函数作为程序入口,先将main函数中的必要信息压入栈中(例如局部变量)
(2)接下来函数会执行main函数中调用的函数func2(x);
*但计算机在运行程序时,会同时把调用的函数以及结束后要执行的代码(以地址的形式)一同压入栈中。是为了在执行结束后能回到相应的地点。
#1 --> c = a + b;
所以我们在func1函数中调用的变量与main函数中定义的变量不在同一块区域,所以它们并不是正真意义的同一个变量,因此我们在func1中修改变量a,b并不会影响main函数中的a,b的值。
(3)接下来在func1中会调用函数func2,同样的。
#2--> x = x+10086
(4)当函数func2执行结束后,就会将栈顶元素弹出栈。
接着执行func1中的 x = x+10086代码。
同样的 func1执行结束后,就会接着执行main函数中的代码。
*栈在递归中的应用
//计算正整数n!
int factorial(int n) {
if (n == 1 || n == 1) {
return 1;
}
else {
return n * factorial(n - 1);
}
}
int main() {
int x = factorial(10);
}
在函数栈中
*#187是执行完后,接着要执行的代码的坐标。
同上,依次执行弹出。
*递归算法,如果递归层数很大,很可能导致栈溢出。也就是递归算法的空间复杂度更大。
队列的应用
先进先出
一,树 的遍历
从一号结点进入,
将一结点压入队列中的同时,也压入一节点的左右两个子结点同时压入队列中。
当遍历完了一结点后,我们将其弹出。同时遍历二号结点的同时将二号结点的子节点加入队列尾部。
二号结点遍历结束后弹出,并执行三号结点的同时加入三号节点的子结点
依次往复便能遍历整个树。