持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情
2022计算机考研408—数据结构—线性表、栈、队列、数组 手把手教学考研大纲范围内的线性表、栈、队列、数组 22考研大纲数据结构要求的是C/C++,笔者以前使用的都是Java,对于C++还很欠缺, 如有什么建议或者不足欢迎大佬评论区或者私信指出
Talk is cheap. Show me the code. 理论到处都有,代码加例题自己练习才能真的学会
循环链栈表
栈的链表
栈和链栈的区别就是顺序表和单链表的区别
入栈和出栈只需要改变指定结点的关系
因为栈是单方向的,所以只需要改变单方向结点的关系
#include "iostream"
using namespace std;
typedef struct StackNode{ //链栈结构体:一个数据,一个指向下一位的指针
int data;
struct StackNode *next;
}StackNode, *LinkStack;
bool InitStackNode(LinkStack &L) { //初始化链栈,直接给链表NULL就可以
L = NULL;
return true;
}
//此压栈方法和单链表的前插法有点类似(如果用后插法,无法访问到上一个结点)
bool Push(LinkStack &L, int data) { //压入data数据进入链栈
StackNode *temp = new StackNode;
temp->data = data; //给temp数据
temp->next = L; //temp的下一个指向L
L = temp; //temp给L
}
bool Pop(LinkStack &L, int &data) { //出栈(把数据传给data)
if (L == NULL) {
return false;
}
data = L->data; //传给data,L指向下一个
L = L->next;
return true;
}
bool Peek(LinkStack &L, int &data) { //返回栈顶元素(给data)
if (L != NULL) {
data = L->data;
return true;
}
return false;
}
void linkStackPrint(LinkStack L) { //输出链栈
while (L) {
cout << L->data << " ";
L = L->next;
}
cout << "\n";
}
int main() {
LinkStack stack;
InitStackNode(stack); //初始化链栈,插入数据
Push(stack,12);
Push(stack,56);
Push(stack,15);
Push(stack,43);
linkStackPrint(stack);
int val;
Pop(stack, val); //栈顶结点出栈
cout << val << "\n";
linkStackPrint(stack);
Peek(stack, val); //返回栈顶元素(不删除栈顶元素)
cout << val << "\n";
linkStackPrint(stack);
Push(stack,15); //入栈
linkStackPrint(stack);
}
递归斐波那契
递归,其实就是自己不断的调用自己,每次改变参数
第五项的斐波那契 就是第四项+第三项
初始值,第一项,第二项的值为1
第三项的值就是前两个相加
第n项就是(n-1)+(n-2) 不断的调用自己
当找到第1项和第2项的时候直接返回1,我们默认第一项和第二项为1 上面的默认值,我们也称为递归的出口
**递归还有很多变种,(DFS,BFS)在后面的博客中会一一细说的**
#include "iostream"
using namespace std;
int f(int n) {
if (n == 1 || n == 2) {
return 1;
}
return f(n - 1) + f(n - 2);
}
int main() {
cout << f(5);
}
递归汉诺塔
/*
根据汉诺塔的规则:一次只能移动一个托盘,而且必须保证小托盘在大托盘上面,完成A的托盘移动到C
设 1号 为最小的托盘,
用递归思路把这个问题分开,如果想把 n 号托盘移动,需要把 n 号上面的托盘都移动了
然后我们转去移动 n-1 号托盘,一直找到最上面的托盘
当移动 1 号托盘的时候,直接移动到C即可
为什么移动n-1号托盘的时候是传入的Hanoi(n - 1, A, C, B)
Hanoi(n, A, B, C) 是把 n 号托盘从A->C
如果 1号 直接移动到C
那么 2号 的时候就要先移动到B,中转一下,(1号 在C,把 1号 移动到B,空出C来给3号)
3号 移动的时候移动到C,(然后再慢慢把B上的转到C上面(!!!并不是一步从B转到C),把B空出来给下一个托盘)
……一直重复如此
不难发现,1->C,2-B,3->C,4->B……
这就是为什么每次都要C和B换位置的原因,n号移动到B,n-1号就要移动到C
!!!所有的A B C都不是固定的ABC 都和这种类似,临时的ABC
(这么做其实就是确保递归时每次都是从当时方法的目的是A->C 而不是一直要自己变动A->B,A->C 把参数改了,方法不变,就达到一直变动的目的了)
当我们 n-1号 托盘移动完成后(同时意味着 1到(n-1) 都移动完成了),我们就可以把 n号 托盘从A直接转到C上
n号移动以后,把1到(n-1)号托盘从B移动到C,重复上面的操作
如果还是不好理解,多看一看动图理解,或者调试调试代码理解,只看不做很难理解
Talk is Cheap, Show me the Code.
*/
**递归中所有的A B C都不是固定的ABC**
#include "iostream"
using namespace std;
int step = 1;
void Hanoi(int n, char A, char B, char C) { //将编号为n的托盘从A移动到C,B当作中间托盘
if (n == 1) {
cout << "步数:" << step++ << " 托盘:" << n << " " << A << "->" << C << "\n";
} else {
Hanoi(n - 1, A, C, B); //把(1-(n-1)号托盘)A->B C做中转结点
cout << "步数:" << step++ << " 托盘:" << n << " " << A << "->" << C << "\n";
Hanoi(n - 1, B, A, C); //把(1-(n-1)号托盘)B->C A做中转结点
}
}
int main() {
Hanoi(3,'A','B','C');
return 0;
}