0425-0429-《王道考研机试》——根据前序、中序表达式进行二叉树的还原。数学相关问题,

数据结构–二叉树

还原一个二叉树,以前序表达式和中序表达式还原为例。

思路分析:建立一颗二叉树有3个步骤

  1. 设置该结点的值。
  2. 设立左子树,然后重复1.2.3步骤
  3. 设立右子树,然后重复1,2,3步骤

因为有重复性的动作发生,且我们也不知道重复的次数,所以我们使用递归来建立二叉树。将上述3个动作体现在代码上为下面

建树函数f(x):
需要四个参数:
当前子树的前序表达式的开始(s1),当前字数的前序表达式的结束(e1)
当前子树的前序表达式的开始(s2),当前字数的前序表达式的结束(e2),
函数体:

  1. 在前序中找到当前子树的根节点,在中序中找到根节点对应位置(pos_r),设置当前子树的根节点的值。
  2. 在中序表达式中,通过pos_r来找到左子树和右子树的长度。
  3. 如果左子树的长度不为空,递归调用当前函数来指向左子树(返回的是一个指向左子树的指针)。
  4. 如果右子树长度不为空,递归调用当前函数来指向右子树(返回的是一个指向右子树的指针)。
  5. 返回当前树的根节点。

完整代码如下:

#include <stdio.h>
#include <string.h>


//知识点涵盖建树,还原,遍历。
struct Node{
    Node *lchild;
    Node *rchild;
    char c;
};
Node Tree[50];

int loc;
//申请一个结点,返回指向该结点的指针。
Node *create(){
    Tree[loc].lchild=Tree[loc].rchild=NULL;
    return &Tree[loc++];
}

char str1[30],str2[30];

void postOrder(Node * T){
    if(T->lchild!=NULL){
        postOrder(T->lchild);
    }
    if(T->rchild!=NULL){
        postOrder(T->rchild);
    }
    printf("%c",T->c);
}

//返回值是一个指向该树的根节点的指针。
Node *build(int beg1,int end1,int beg2,int end2){
        //beg1->end1是要构建的树的前序表达式, beg2->end2是要构建的树的中序表达式。
        //1.根据前序表达式找到根节点并在中序表达式中定位
        char root=str1[beg1];      //在前序表达式中找到根节点
        Node *T=create();
        T->c=root;
        int flag=0;
        int i=0;
        for(i=beg2;i<=end2;i++) {//在中序表达式找到根节点的位置.
            if(str2[i]==root){
                flag=1;
                break;
            }
        }

        //2.用递归的方法构造左子树和右子树.

        //分别计算左子树和右子树的长度
        int llength=i-beg2;
        int rlength=end2-i;

        //左右子树不为空的时候,才会构建。
        if(llength!=0)
            T->lchild=build(beg1+1,beg1+llength,beg2,beg2+llength-1);
        if(rlength!=0)
            T->rchild=build(beg1+llength+1,end1,i+1,end2);
        return T;
}

int main(){
    while(scanf("%s",str1)!=EOF){
        scanf("%s",str2);
        loc=0;
        int L1=strlen(str1);
        int L2=strlen(str2);
        Node *T=build(0,L1-1,0,L2-1);
        postOrder(T);
        printf("\n");
    }
    return 0;
}

数学问题-数位拆解

数学原理

这个接触过的人都应该明白.就不多废话了。直接附上代码

int a; //输入的数字
    while(scanf("%d",&a)!=EOF){
        int buf[20],size1=0;

        if(a==0){ //输入的就是0
            buf[0]=0;
        }
        else {    //输入的不是0
            while(a!=0){
            buf[size1++]=a%10;
            a/=10;
            }
        }
		//buf[i]是依次从低位向高位输出。
        for(int i=0;i<size1;i++){
            printf("%d ",buf[i]);
        }
    }

使用字符串解决

这个相对来说还是比较新颖的。代码附上

char a[20];
    int b[20];
    while(scanf("%s",a)!=EOF){
        int ans=0;
        for(int i=0;a[i]!=0;i++){
            b[i]=a[i]-'0';
            printf("%d ",b[i]);
        }
    }

用字符串解决代码很少哈。以后可能更多用这个咯~

数学原理-素数相关问题

素数:除了1和自身,无法被其他数字整除的数叫做素数。

判断一个数是否是素数

关键: 判断n是否是素数,我们的判断规模不应该是1->n,而是1->sqrt(n)。
代码

bool decide(int a){
    int bound=(int)sqrt(a)+1; //sqrt()求出来的是一个Double.用int进行截断
    bool flag=true;
    for(int i=2;i<=bound;i++){
        if(a%i==0){
            flag=false;
            break;
        }
    }
    return flag;
}

输出1到指定数字的所有素数

关键: 如果每次输入一个数字,都要从1重新开始判断的话,就做了很多重复性的工作,而如果数据的规模给了我们,我们可以提前将数据规模的素数直接筛选出来。(利用了Hash的思想)

关键解题思路: 如果一个数字不是素数,那么它一定由较小的数字的乘积组成,初始化数组为全是素数,我们从2开始寻找,如果找到一个数字是素数,就将数据规模内该素数的倍数全部置为非素数。这样我们便可以找出所有的素数了。时间复杂度<O(n^2).
代码

#include <stdio.h>
#include <math.h>

bool is_sushu[10000];  //true表示是素数。
int prime[10000];       //保存得到的素数。
int prime_num=0;        //素数的总个数

void init(){
    for(int i=0;i<10000;i++){
        is_sushu[i]=true;  //一开始假定全都不是素数。
    }
    for(int j=2;j<10000;j++){
        if(is_sushu[j]==false){ //这个数字不是素数,已经被标记过了
            ;
        }
        else {
            //这个数字是素数,我们将其倍数都置为非素数
            prime[prime_num]=j;
            prime_num++;
            //注意这里k的初始值为什么是j*j. 而不是j. 因为 j*2,j*3的数字在判断2 和3 的倍数的时候已经判断过了。这里是一个技巧(减小数据规模)
            for( int k=j*j;k<10000;k+=j){
                is_sushu[k]=false;
            }
        }
    }
}

//题目要求,输入一个数,输出从1到这个数字的所有素数。
int main(){

    //解题想法:根据数据规模,利用哈希存储,提前将每个数是否是素数放在数组中。
    //每输入一个数都重新从1开始判断一次太费时间,所以我们提前将数据规模的数字是否是素数全部计算出来。
    //怎样计算素数? 我们碰见一个素数,就将数据规模内的该素数的倍数全部置为非素数。

    int num;
    scanf("%d",&num);
    init();
    for(int i=0;i<prime_num;i++){
        if(prime[i]<num){
            printf("%d ",prime[i]);
        }
        else break;
    }
    return 0;
}

数位问题——最大公约数和最小公倍数

关键理解

最小公约数: 求a和b的最大公约数,等同于求a和a%b的最大公约数。
最大公倍数: a和b的最大公倍数就是a*b/x; x为a,b的最大公约数.

思路理解:

  1. 如果a,b均为0,则无最大公约数
  2. 如果a,b其中一个为零,则另一个数就是最大公约数
  3. 如果a,b都不等于0,则等效于求a,a%b的最大公约数。

代码

int gcd(int a,int b){
    if(b==0) return a;
    else return gcd(b,a%b);
}

总结

这几天的学习效果不是很好噢.原因还是每天睡得太多了。。。。我发现我学习的时候不能有东西打扰,一打扰就泄劲了。就学不进去了。。。
以后继续加油!

根据前序遍历和中序遍历结果构建二叉树是一种常见的算法问题前序遍历的顺序是根节点 -> 左子树 -> 右子树,中序遍历的顺序是左子树 -> 根节点 -> 右子树。通过这两个遍历结果,我们可以构建出原始的二叉树结构。 构建过程大致可以分为以下步骤: 1. 前序遍历的第一个元素总是树的根节点。 2. 在中序遍历结果中找到根节点的位置,这将中序遍历结果分为两部分,左边是所有左子树的节点,右边是所有右子树的节点。 3. 根据中序遍历中左子树和右子树的节点数量,可以在前序遍历结果中分割出左子树和右子树的前序遍历序列。 4. 递归地使用上述方法分别构建左子树和右子树。 具体实现时,可以用一个辅助函数来进行递归操作,函数接收前序遍历序列和中序遍历序列的子序列,返回构建好的子树的根节点。 这里提供一个简化的伪代码示例: ``` function buildTree(preorder, inorder) { if (preorder.length == 0 || inorder.length == 0) { return null; } // 前序遍历的第一个值是根节点 let rootVal = preorder[0]; let root = new TreeNode(rootVal); // 在中序遍历中找到根节点的位置 let midIndex = inorder.indexOf(rootVal); // 构建左子树 root.left = buildTree(preorder.slice(1, midIndex + 1), inorder.slice(0, midIndex)); // 构建右子树 root.right = buildTree(preorder.slice(midIndex + 1), inorder.slice(midIndex + 1)); return root; } ``` 注意:这个伪代码仅为了说明构建过程,实际实现时可能需要处理一些边界情况,并且在实际编程语言中可能需要根据具体语言特性进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值