4.25-4.29日
数据结构–二叉树
还原一个二叉树,以前序表达式和中序表达式还原为例。
思路分析:建立一颗二叉树有3个步骤
- 设置该结点的值。
- 设立左子树,然后重复1.2.3步骤
- 设立右子树,然后重复1,2,3步骤
因为有重复性的动作发生,且我们也不知道重复的次数,所以我们使用递归来建立二叉树。将上述3个动作体现在代码上为下面
建树函数f(x):
需要四个参数:
当前子树的前序表达式的开始(s1),当前字数的前序表达式的结束(e1)
当前子树的前序表达式的开始(s2),当前字数的前序表达式的结束(e2),
函数体:
- 在前序中找到当前子树的根节点,在中序中找到根节点对应位置(pos_r),设置当前子树的根节点的值。
- 在中序表达式中,通过pos_r来找到左子树和右子树的长度。
- 如果左子树的长度不为空,递归调用当前函数来指向左子树(返回的是一个指向左子树的指针)。
- 如果右子树长度不为空,递归调用当前函数来指向右子树(返回的是一个指向右子树的指针)。
- 返回当前树的根节点。
完整代码如下:
#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的最大公约数.
思路理解:
- 如果a,b均为0,则无最大公约数
- 如果a,b其中一个为零,则另一个数就是最大公约数
- 如果a,b都不等于0,则等效于求a,a%b的最大公约数。
代码
int gcd(int a,int b){
if(b==0) return a;
else return gcd(b,a%b);
}
总结
这几天的学习效果不是很好噢.原因还是每天睡得太多了。。。。我发现我学习的时候不能有东西打扰,一打扰就泄劲了。就学不进去了。。。
以后继续加油!