22计算机408考研—数据结构—循环链栈表

313 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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;
}

在这里插入图片描述