老师在算法分析课堂上向我们介绍了一下如何使用非递归的方式来实现先序访问一棵树。
于是写了一个小程序测试了一下。没有什么过深的理论, 或许连基本的算法也谈不上,
也没有什么十分明确的目的,
这篇博文专门用来记录一些零碎时间编程实现的一些小程序;从今以后小片段的代码就往这个博客中甩了。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
using namespace std ;
struct node
{
char _v ;
node *_right , *_left ;
node (char v ) : _v(v) , _right (nullptr) , _left(nullptr)
{}
node () {}
} ;
typedef node TreeNode ;
typedef TreeNode *TreeRoot ;
void createTree ( TreeRoot &root )
{
char c ;
cin>>c ;
if (c=='#' )
{
root = nullptr ;
return ;
}
else
{
root = new node (c) ;
createTree(root->_left) ;
createTree(root->_right) ;
}
}
void searchTree ( TreeRoot root )
{
if(root == nullptr )
return ;
cout<<root->_v<<endl ;
searchTree(root->_left) ;
searchTree(root->_right ) ;
}
void searchTree2( TreeRoot root )
{
if ( root == nullptr ) return ;
TreeNode *p = root ;
stack<TreeNode *> s ;
while ( p || !s.empty() )
{
while (p)
{
cout<<p->_v<<endl ;
s.push(p) ;
p= p->_left ;
}
p = s.top () ;
s.pop () ;
p = p->_right ;
}
}
int main ( void )
{
TreeRoot T ;
createTree(T) ;
searchTree(T) ;
searchTree2(T) ;
system("pause") ;
return 0 ;
}
我第一次写的时候, 在main 中创建的是一个指针的TreeNode 变量, 但是在子方法调用中并不能实现对传入参数在主方法的修改。
然后,想到这里定义的TreeNode 对象实质上是一个复杂的类型(不是int , char 这种原生语言中定义的类型)所以考虑到使用引用。
于是将传递的参数写成 TreeNode & *root , 但是IDE编译环境会提示有错误, 我觉得这个地方应该是在传递引用的时候应该使用const 来对
指针变量或是某一个部分进行修饰,(这个我稍后查一下)。才能够保证正常的格式要求。
于是我再次定义了一个TreeRoot 的类型, 这个类型本质上就是 TreeNode * 的重定义,这样的话引用是针对 TreeRoot 类型的,一切变得顺理成章了。
11_19
今天总结了一下上一节课老师将的两个程序,是关于递归方面的算法实现。
问题一,任何一个正整数都是可以使用一个 2 的幂次方来进行表示的。
问题分析:
这个问题可以通过递归方法来求得。
首先,在使用递归方法求解问题的时候,应该知道应该以何种方式来化解问题,
将其从一个复杂的问题化简为满足基础问题条件的元问题。
例如使用 5 , 每次与2 取余数,然后记录余数,并将 5 除上数值 2 ,
然后在进行与 2 取余数,直至当前数值为 1 时停止。
所以,由此可得知,元问题的条件是: n == 1 , 此时求出的余数将作为二进制数列中的最高位,
若在每次取余操作之后,通过一个数值进行对当前位数进行累计的话,设其为 r ,
则,n = 1 的时候, r 数值对应的即为 2^r 将作为二进制累加成为 n 的一部分。
若使用函数来进行表示的话,有:
void func ( int n , int r ) ;
n = 5 , r = 0 => n = n/2 , r++ ;
n = 2 , r = 1 => n = n/2 , r++ ;
n = 1 , r = 2 =====> 达到元问题 ,n = 1 ,
于是向上进行回溯, 不过在回溯的过程中有一点要注意,
你看,对于数值 5 来说,r 的数值从 0 -> 2 , 对应的分别是
2^2 , 2^1 , 2^0 这三种情况被遍历到,但是被遍历并不代表者被选中,
是否选中,还需要分析当时的 n 值, 比如说,在 n = 2 的时候,r =1 , 2%2 = 0, 即 , 2 为偶数的时候,对应与 2 取余数的值是 0 ,
所以 r = 1 即, 2^1 这个数值是不能作为 5 的加数的。(101 = 5 )
所以说,在回溯的时候,跑出掉所有的 n 值为偶数的情况。
(在这里所说的元问题就是指,整个递归函数最初始的那个基础解,也是所有递归函数的出口,
在递归函数中的某些条件还没有达到初始条件的时候,不能进行最终计算,只能够不断的向下分解问题的规模)
x= 56 , 则计算的过程是这样的
1, func ( 56 , 0 ) : n = 56/2= 28 , r= r+1 = 1 ;
2, func ( 28 , 1 ) : n = 28/2 = 14 , r = r+1 = 2 ;
3, func(14 , 2 ) : n = 14/2 = 7 , r = r+1 = 3 ;
4,func(7,3 ) : n = 7/2 = 3 , r = 4;
5,func(3,4) : n = 1 , r = 5 ;
5,func: n=1 , r = 5 ; n%2 != 0 output 2^5 = 32
4,func: n=3, r = 4 ; n%2 != 0 output 2^4 = 16
3,func n = 7, r = 3 ; n%2 != 0 output 2^3 = 8
2,func n =14 ,r =2 ; n%2 == 0 , no output
1, func n = 28 , r = 1 ; n%2 == 0 ,no output
0, func n = 56 , r = 0 , n %2 == 0 , no output
#include <cstdio>
#include <cstdlib>
#include <stdio.h>
#include <string>
int a [101] ={0}, len = 0 ;
void func ( int n , int r )
{
if (n==1)
{
printf(" 2^%d ", r ) ;
}
else
{
func( n/2 , r+1 ) ;
//first decompose the scale of the problem
//then output the information during the process of backtracing
if ( n%2 )
{
printf(" 2^%d " , r ) ;
}
}
}
//if there is other requirements , we can use the array store the value before recursive algorithm
int func2( int n , int r )
{
if ( n==1 )
{
a[r] = 1;
return r ;
}
else
{
a[r] = n%2 ;
//here , with the help of the array ,we can first store the value ,then decompose the problem's scale
return func2(n/2 , r+1) ;
}
}
int main ( int argc , char * argv[] )
{
int x ,i ;
func(56 , 0 ) ;
x = func2(56 , 0 ) ;
printf("\n 56 = ") ;
for ( i = x ; i >= 0 ; i-- )
{
if ( a[i] )
printf(" 2^%d ", i) ;
if ( i != 0 )
printf("+") ;
}
system("pause") ;
return 0 ;
}
还有一个,排列组合的程序。