注意:链表为空。是否越界访问。每写一步都要思考该步是否会有越界(多/少)等问题。这一步是否有不能走的条件(删除的时候不为空)。只有该节点开辟了空间,该节点才能被指向。能用c++就用c++。#include <iostream> #include <queue> using namespace std;queue<int> ji,ou;。二叉树遍历过程中,注意递归终止条件是否会导致子树没有遍历就退出了,每一层返回的值要单独用一个变量保存下来。用顺序表访问二叉树的双亲、孩子节点时,一定要注意是否越界。最后数组大小别忘记++/--。
1.在循环中,最好让循环条件的变量代表的是当前元素,而不是当前元素的下一个位置
//不断插入一个元素,是最后生成的顺序表是有序顺序表:
2.创建单链表的方法:
注意:参数表中的链表要传引用;定义两个指针;一定要记得首先给L malloc一块空间。
当遇到输入不正常时,首先检查是否所有指针都开辟空间了。
3.切记有指针就一定要开辟空间。
4.一定要注意空指针域不能访问,一定要及时判断该节点或者该节点的下一个节点是否为空。
5.如果出错的时候:分析链表为空时、只有一个节点时、有两个节点时、有三个节点时......
* * * 带头结点的单链表就地逆置
//这种方法最简单
//headptr用来记录下一个midptr应该指向的节点
6.出现运行超时可能是链表出现了死循环。出现段错误大概率是数组越界访问了。
7.要求实现一个对数组进行循环右移的简单函数:一个数组a中存有n(>0)个整数,将每个整数循环向右移m(≥0)个位置,即将a中的数据由(a0a1⋯an−1)变换为(an−m⋯an−1a0a1⋯an−m−1)(最后m个数循环移至最前面的m个位置)。
前后两组分别逆置即可实现。注意:注意有m>n的情况,让m%=n。
8.不要忘记了前后指针法。
9.有时候让删除数据的时候,为了让代码简便,可以在这个结构体内部定义一个变量标记一下是否被删掉了,这样就可以不用删除了,打印的时候不打印就可以了。
10.
char* xuehao; scanf("%s", xuehao);遇到空格就不读入了
#include <iostream> #include <string> string delet;cin>>delet;也是遇到空格就不读了
#include <stdio.h> char str[100]; gets(str);可以读入空格
#include <iostream> #include <string> string str; getline(cin, str);可以读入空格
while(scanf("%c",&s)&&s!='\n')可以输入一行字符
11. #include <string.h>
(strcmp(tmp, arr->stu[i].xuehao))//相等返回零,不相等返回正数
12.
//注意初始值最好弄成-1,而不是1
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>int main()
{int *a,*b;int ma=0;int c,d;a=(int*)malloc(10000*sizeof(int));// b=(int*)malloc(10000*sizeof(int));int n,m;scanf("%d %d",&n,&m);for(int i=0;i<n;i++){scanf("%d",&c);if(c>ma)ma=c;a[c]=-1;//注意初始值最好弄成-1,而不是1}for(int i=0;i<m;i++){scanf("%d",&d);a[d]++;}int tmp=0;for(int i=0;i<=ma;i++)//注意是<={if(a[i]==-1){tmp=1;printf("%d ",i);}}if(tmp==0)printf("0");return 0;
}
13.链表后移p=p->next。 顺序表后移p++。
14.Status ListCreate_L(LinkList &L,int n):当需要改变参数时,记得要传引用。
15.对带头结点的单链表的就地逆置。
void ListReverse_L(LinkList &L)
{LinkList pre,pb,nex;pre=L;if(!L)exit(OVERFLOW);pb=L->next;//注意这个循环条件,因为循环内部对pb的next进行访问了//必须保证下一个也是非空指针//否则会出现段错误while(pb->next){nex=pb->next;pb->next=pre;pre=pb;pb=nex;}if(pb->next==NULL)pb->next=pre;L->next->next=NULL;L->next=pb;
}
16.
当创建了一个新链表时,一定记得实现开辟头结点的空间,让尾指针指向头节点,然后开辟每个结点的空间,尾指针的next指向该节点,尾指针后移。
当进行链表的合并时,注意链表的余块不要忘记处理。
17.求链表倒数第k个数:
另一个方法:双指针法,后指针位于第k个节点,前指针位于第一个节点。前后指针都后移,后指针走到结尾,前指针指向的位置就是倒数第k个。
注意:防止越界(假如有三个数,结果求倒数第八个)。
//count为倒数第几个,n为链表中有几个节点
void ListFind(li s,int count,int n)
{li ps=s->next;//别忘了假如有三个数,结果求倒数第八个if(count-n<0)//3 1 2 3 -1{printf("NULL");return;}for(int i=0;i<count-n;i++){//在其间走到空也要结束if(!ps){printf("NULL");return;}ps=ps->next;}if(ps)printf("%d",ps->e);elseprintf("NULL");
}
18.设有一个双向循环链表,每个结点中除有left、data和right三个域外,还增设了一个访问频度域freq,freq 的初值为零。每当链表进行一次查找操作后,被访问结点的频度域值便增1,同时调整链表中结点的次序,使链表按结点频度值非递增有序的次序排列。
typedef struct Node{
ElemType data;struct Node *left;struct Node *right;
intfreq;
} DNode;
DNode *locate_DList(DNode *&L, ElemType x)
{ //在表L中查找元素x,查找成功则调整结点频度域值及结点位置,并返回结点地址;
//查找不成功则返回NULL
DNode *p=L, *q;if (L==NULL) return NULL;while (p->data!=x && p->right!=L) p=p->right;if (p->data!=x) return NULL;p->freq++;q=p->left;while (q!=L && q->freq<=p->freq) q=q->left; //查找插入位置if (q==L && q->freq<=p->freq) { //需将p结点插在头结点L前
//将p结点先从链表中摘下来
p->left->right=p->right;p->right->left=p->left;//将p结点插在L结点前p->right=L;p->left=L->left;L->left->right=p;L->left=p;L=p;}else if (q!=p->left ) { //若q不是p的前驱,则需调整结点位置,将p结点插在q结点后
//将p结点先从链表中摘下来p->left->right=p->right;p->right->left=p->left;p->left=q;//将p结点插在q结点后p->right=q->right; q->right->left=p; q->right=p;}return p;
}
19.//在带头结点的双向链表L中第i个位置之前插入元素e,i的合法值为1≤i≤表长+1。
20.删除循环单链表某个节点。注意循环边界条件。注意释放被删节点的空间。
void ListDelete_CL(LinkList &CL, ElemType min, ElemType max)
{LNode* p=CL->next;LNode* pre=CL;while(p!=CL){if(p->data>min&&p->data<max){pre->next=p->next;LNode* pp=p;free(pp);p=pre->next;}else{pre=pre->next;p=p->next;}}
}
21.双向循环链表操作集。
typedef int dataType;typedef struct _node
{dataType data;struct _node *prev;//指向前驱的指针struct _node *next;//指向后继的指针
}node;typedef node* List;#define OVERFLOW -2
#define OK 1
#define ERROR 0
//创建一个空的循环链表,返回指向头节点的指针。
List create_list()
{node* p=(node*)malloc(sizeof(node));if(!p)exit(OVERFLOW);p->next=p;p->prev=p;return p;
}
//用尾插法向链表L中插入数据域等于x的结点
void insert(List L, dataType x)
{node* p=(node*)malloc(sizeof(node));if(!p)exit(OVERFLOW);p->data=x;node* ppt=L;p->prev=ppt->prev;p->next=ppt;ppt->prev->next=p;ppt->prev=p;
}
//如果链表为空,则返回true,否则返回false。
bool is_empty(List L)
{if(L->next==L&&L->prev==L)return true;elsereturn false;
}
//顺序遍历链表L。输出所有结点的数据域。如果链表为空则输出NULL
void traverse(List L)
{node* p=L->next;if(L->next==L&&L->prev==L)printf("NULL\n");else{while(p!=L){printf("%d ",p->data);p=p->next;}printf("\n");}
}
//逆序遍历链表L。输出所有结点的数据域。如果链表为空则输出NULL
void traverse_back(List L)
{node* p=L->prev;if(L->next==L&&L->prev==L)printf("NULL\n");else{while(p!=L){printf("%d ",p->data);p=p->prev;}printf("\n");}
}
//返回第1个指向数据域等于x的结点的指针。如果没有则返回NULL。
node* search(List L, dataType x)
{node* p=L->next;while(p!=L){if(p->data==x){return p;}p=p->next;}return NULL;
}
//删除指针p指向的结点。调用者保证p是合法的。
//返回p指向结点后继结点的指针。
//若p指向链表最后一个结点,返回指向头结点的指针。
node* delete_node(List L, node* p)
{node* ptr=L->next;while(ptr!=L){if(ptr==p){node* pp=ptr->next;ptr->prev->next=ptr->next;ptr->next->prev=ptr->prev;free(ptr);return pp;}ptr=ptr->next;// !!!!!!}if(ptr==L&&ptr==p){node* pp=p->next;ptr->prev->next=ptr->next;ptr->next->prev=ptr->prev;free(ptr);return pp;}
}
//删除链表L中所有数据域等于x的结点
void remove_node(List L, dataType x)
{node* ptr=L->next;while(ptr!=L){if(ptr->data==x){ptr->prev->next=ptr->next;ptr->next->prev=ptr->prev;free(ptr);}ptr=ptr->next;// !!!!!}
}
//使链表L成为一个空链表
void make_empty(List L)
{L->next=L;L->prev=L;
}
//销毁链表L
void destroy_list(List L)
{L->prev->next=NULL;node* p=L;node* tmp;while(p){tmp=p;p=p->next;free(tmp);}
}
22.符号配对:
首先将所有要判断的符号入栈(用栈实现顺序表实现顺序表时,定义的结构体中包含数组指针和top指针指向数组尾部第一个没有元素的位置)。
然后判断左括号入栈,遇到右括号分三种情况:栈顶元素为左括号;栈空,则保存下来这个右括号;栈不空,则保存下来这个左括号。
然后判断是否这个保存符号的变量是否为初始值:为初始值且栈为空则匹配成功;为初始值但是栈不空,则取栈底元素。不为初始值就只需按照上一步保存下来的符号来输出打印即可。
23.递归创建链表。
24.快速求最大最小值(分治法),类似二分法
//类似二分法
int max(int *a,int m,int n)
{int mid;if(m==n)return a[m];else{mid=(m+n)/2;int left=max(a,m,mid);int right=max(a,mid+1,n);//一半一半的分开,最后成为前后两半的两个元素相比较//一层一层选出最大的返回出来然后比较//最里层只有一个数,把两个最里层的数返回比较if(left<right){return right;}else{return left;}}
}
int min(int *a,int m,int n)
{int mid;if(m==n)return a[m];else{mid=(m+n)/2;int left=min(a,m,mid);int right=min(a,mid+1,n);//一半一半的分开,最后成为前后两半的两个元素相比较//一层一层选出最大的返回出来然后比较//最里层只有一个数,把两个最里层的数返回比较if(left<right){return left;}else{return right;}}
}
25.n皇后问题
#include <stdio.h>
#include <stdlib.h>
#define N 20 //最多皇后个数
int q[N]; //存放各皇后所在的列号,即(i,q[i])为一个皇后位置void dispasolution(int n) //输出n皇后问题的一个解
{for (int i=1;i<=n;i++)printf("(%d,%d)",i,q[i]);printf("\n");
}bool place(int i,int j) //测试(i,j)位置能否摆放皇后
{if (i==1) return true; //第一个皇后总是可以放置int k=1;while (k<i) //k=1~i-1是已放置了皇后的行{ if ((q[k]==j) || (abs(q[k]-j)==abs(i-k)))return false;k++;}return true;
}
void queen(int i,int n);int main()
{ int n; //n为存放实际皇后个数scanf("%d",&n);if (n<=20)queen(1,n); //放置1~i的皇后return 0;
}
void queen(int i,int n)
{if(i>n)//放置完了n个皇后{dispasolution(n);return;}else{for(int j=1;j<=n;j++)//在每一个i行试探每一个j列{if(place(i,j)){q[i]=j;//表示这个位置可行queen(i+1,n);//下一行即下一个皇后//假如j列不可以,就返回到这里,然后进行下一次for循环,试探j+1列是否可行}}}
}
26.求逆序数,用二路归并法(一边排序一边找)。
#include <iostream>
#include<algorithm>
#include<stdio.h>
#include<malloc.h>
#define N 1000
using namespace std;
int ans=0;void Merge(int a[],int low,int mid,int high);
void mergesort(int a[],int low,int high);int main()
{int a[N],n;cin>>n;for(int i=0;i<n;i++)cin>>a[i];mergesort(a,0,n-1);cout<<ans;return 0;}void Merge(int a[],int low,int mid,int high)
{int lindex=low,rindex=mid+1;int team[high-low+1];int teamindex=0;while(lindex<=mid&&rindex<=high)//这里注意每部分的截止条件{if(a[lindex]<=a[rindex]){team[teamindex++]=a[lindex++];}else{team[teamindex++]=a[rindex++];//ans++;//不对ans+=mid-lindex+1;//加上左侧还剩余的//为什么只有这个else条件需要加呢//因为前提是你这两部分已经是有序的了,当lindex<rindex时,//在左边那部分中lindex小于左边所有的数据,而lindex小于rindex,即小于右边所有的元素,//所以把他前移不会影响逆序数的数量,因为对lindex来说不存在逆序数//但当rindex小于lindex时,rindex小于左边所有的元素(小于左边存在逆序数),//也小于右边所有的元素(小于右边不存在逆序数)//所以改变的逆序数的数量即为左边所有元素的数量}}//这两个while循环最后只执行一个,因为只有一个走到头了才会结束上面那个循环while(lindex<=mid){team[teamindex++]=a[lindex++];}while(rindex<=high){team[teamindex++]=a[rindex++];}for(int i=0;i<teamindex;i++){a[low+i]=team[i];//注意a的下标从哪里开始,因为是一层一层的}
}
void mergesort(int a[],int low,int high)
{if(low<high){int mid=(low+high)/2;//这个函数调用顺序是最先两个元素比较排序,在排序的过程中判断有没有逆序数mergesort(a,low,mid);mergesort(a,mid+1,high);Merge(a,low,mid,high);}
}
27.输出全排列(不重复)
eg:3---123、132、213、231、312、321
#include <stdio.h>
int a[15]= {0};
int books[15]= {0}; //用来记录这个数字出现没有
void Print(int a[],int n)
{for(int i=1; i<=n; i++){printf("%d",a[i]);}printf("\n");
}
void go(int a[],int n,int step)
{if(step>n){Print(a,n);return;}else{for(int i=1; i<=n; i++){if(books[i]==0){books[i]=1;a[step]=i;go(a,n,step+1);a[step]=0;//step=i这一步试探结束,再往前(step-1)回溯了books[i]=0;}}}
}
int main()
{int n;scanf("%d",&n);go(a,n,1);
}
28.整数分解。
#include <stdio.h>
int n;
int a[40];
int cnt=0;
void dfs(int num,int location,int sum)//第一个参数为当前因子的大小
{//上一层传进来的是location+1,相当于已经多了一位了,所以循环的时候i<locationif(sum==n){for(int i=1; i<location; i++){if(i==1)printf("%d=%d",n,a[i]);elseprintf("+%d",a[i]);}cnt++;if(cnt%4==0||num==n)//第二个条件表明当只有一个因子时输出回车printf("\n");else if(cnt%4!=0)printf(";");}else if(sum<n){for(int j=num; j<=n; j++){a[location]=j;dfs(j,location+1,sum+j);//第一个参数得是ja[location]=0;}}else//需要有退出的条件,不能只有上面两个判断条件//否则卡在第一次调用中无法回溯return;
}
int main()
{scanf("%d",&n);dfs(1,1,0);
}
29.求最大子段和。
中心思想就是规避负数。
30.求解简单装载问题(回溯法)
//剪枝
//对于第i层的某个分枝结点,对应的调用状态是dfs (num, tw, rw, op,i) ,对应的扩展结点有2个:
//左分支:
// ●选择第i个
// ➢op[i]=1 , num=num+1, tw=tw+w[i], rw=rw-w[i],转到下一个状态dfs(num, tw, rw,op,i+1)
//右分支:
// ●不选择第i个,
// ➢op[i]=0, num不变, tw不变, rw=rw-w[i] ,转到下一 个状态dfs (num, tw, rw, op,i+1)
//默认选择左分支,到这一层发现超出重量了,便回溯到上一个节点,选择右分支,既不选择这个点
//选择过程呈现为一棵倒立的二叉树
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 20 //最多集装箱个数
//问题表示
int w[MAXN]={0}; //各集装箱重量,不用下标0的元素
int n,W;
int maxw; //存放最优解的总重量
int x[MAXN]; //存放最优解向量
int minnum=999999; //存放最优解的集装箱个数,初值为最大值
void dfs(int num,int tw,int rw,int op[],int i);
void dispasolution(int n) //输出一个解
{for (int i=1;i<=n;i++)if (x[i]==1)printf("%d ",i);
}
int main()
{int i;cin>>n>>W;for(int i=1;i<=n;i++)cin>>w[i];int op[MAXN]; //存放临时解memset(op,0,sizeof(op));int rw=0;for (int i=1;i<=n;i++)rw+=w[i];dfs(0,0,rw,op,1);dispasolution(n);return 0;
}
//其中num表示选择的集装箱个数,tw表示选择的集装箱重量和,
//rw表示剩余集装箱的重量和,
//op表示一个解,即一个选择方案,i表示考虑的集装箱i。
void dfs(int num,int tw,int rw,int op[],int i)
{if(i>n)//i从1开始{if(tw==W&&num<minnum){minnum=num;for(int j=1;j<=n;j++){x[j]=op[j];}}}else{op[i]=1;if(tw+w[i]<=W)//只有重量没超才会继续向下递归,这就是边界条件{dfs(num+1,tw+w[i],rw-w[i],op,i+1);}//下面是另一个分支//两个分支一定都要走一遍,所以这样并行排列op[i]=0;if(tw<=W){dfs(num,tw,rw,op,i+1);//注意是rw-w[i],因为舍弃了这一个集装箱了//传rw也可以,没有影响}}
}
31.0/1背包问题(回溯法)要求价值最大
#include <stdio.h>
#include <string.h>
#include <iostream>
#define MAXN 20 //最多物品数
using namespace std;
int n; //物品数
int W; //限制重量
int w[MAXN]={0}; //存放物品重量,不用下标0元素
int v[MAXN]={0}; //存放物品价值,不用下标0元素
int x[MAXN]; //存放最终解
int maxv; //存放最优解的总价值
void dfs(int i,int tw,int tv,int rw,int op[]);
void dispasolution() //输出最优解
{ int i;for (i=1;i<=n;i++)if (x[i]==1)printf("%d ",i);printf("\n%d %d",W,maxv);
}
int main()
{int i;cin>>n>>W; //输入物体个数及背包载重量for(int i=1;i<=n;i++)//输入各物体重量及价值cin>>w[i]>>v[i];int op[MAXN]; //存放临时解memset(op,0,sizeof(op));int rw=0;for (int i=1;i<=n;i++)rw+=w[i];dfs(1,0,0,rw,op);dispasolution();return 0;
}
//就按照这个if和else分析
//注意else中的写法
void dfs(int i,int tw,int tv,int rw,int op[])
{if(i>n){if(tw==W&&tv>maxv){// W=tw;maxv=tv;for(int i=1;i<=n;i++){x[i]=op[i];}}}else{op[i]=1;if(tw+w[i]<=W){dfs(i+1,tw+w[i],tv+v[i],rw-w[i],op);}op[i]=0;if(tw<=W){dfs(i+1,tw,tv,rw,op);}}
}
32.循环队列操作集。
typedef struct _queue
{int front;//队头指针int rear;//队尾指针int *data;//指向数据区
}queue;
#include <malloc.h>
//创建一个空队列
int capacity=MAXSIZE;
queue* createQueue()
{queue* Queue;//这个地方切记要给这个指针开辟空间Queue=(queue*)malloc(sizeof(queue));Queue->data=(int*)malloc(capacity*sizeof(int));if(!Queue->data)exit(-1);Queue->front=Queue->rear=0;return Queue;
}
//入队
void enQueue(queue* q, int x)
{//注意这是循环链表,不用多开辟空间if(q->rear==capacity){//capacity*=2;//q->data=(int*)realloc(q->data,sizeof(int)*capacity);//if(!q->data)//exit(-1);q->rear=0;}q->data[q->rear++]=x;
}
//判断队列是否已满
bool isFull(queue* q)
{//注意循环链表,rear可能小于front//因为循环链表不好判断队满还是队空,因为都是rear=front//所以规定满的情况是rear后面的那一块空间不存储,再下一块空间才是frontif((q->rear+1)%capacity==q->front)return true;elsereturn false;
}
//出队
void deQueue(queue* q)
{if(!isEmpty(q))q->front++;
}
//得到队头元素的值
int front(queue* q)
{return q->data[q->front];
}
//判断队列是否为空
bool isEmpty(queue* q)
{if(q->front==q->rear)return true;elsereturn false;
}
//返回队列长度
int size(queue* q)
{//注意判断方式//把下面这两种情况结合起来//rear-front//rear-front+capacityreturn (q->rear-q->front+capacity)%capacity;
}
//销毁队列
void destroyQueue(queue* q)
{if(!q->data)return;free(q->data);q->data=NULL;q->front=q->rear=0;
}
33.双端队列操作。
头指针指向的有元素,先移动再赋值。
尾指针指向的是空的空间,先赋值再移动。
typedef int Position; /* 整型下标,表示元素的位置 */
typedef struct DequeNode *Deque;
struct DequeNode {int capacity; /* 双端队列的容量 */Position front; /* 双端队列的队首指针,初始化为0 */Position rear; /* 双端队列的队尾指针,初始化为0 */QElemSet *data; /* 存储数据的数组 */
};
void InitDeque(Deque deque, int n)
{ /* 注意:为区分空队列和满队列,需要多开辟一个空间 */deque->data = (QElemSet *)malloc(sizeof(QElemSet) * (n+1));deque->front = deque->rear = 0;deque->capacity = n+1;
}//是循环存的,前面插入元素在开头的话,那么下一个头插的就要插在尾部
//这两个指针指向的位置都是空的,就是说插入这个位置,指针再移动即可
//头插
bool EnQueue(Deque deque, QElemSet x)
{if((deque->rear+1)%(deque->capacity)==deque->front)return false;else{//保证循环起来deque->front=((deque->front-1)+deque->capacity)%deque->capacity;deque->data[deque->front]=x;return true;}
}
//头删
QElemSet DeQueue(Deque deque)
{if(deque->front==deque->rear)return ERROR;else{QElemSet q=deque->data[deque->front];deque->front=(deque->front+1+deque->capacity)%deque->capacity;return q;}
}
//尾插
bool Inject(Deque deque, QElemSet x)
{if((deque->rear+1)%deque->capacity==deque->front){return false;}else{deque->data[deque->rear]=x;deque->rear=(deque->rear+1)%deque->capacity;return true;}
}
//尾删
QElemSet Eject(Deque deque)
{if(deque->front==deque->rear)return ERROR;//单独分析这种情况,因为0再减一就是-1,数组越界了if(deque->rear==0){deque->rear=deque->capacity;//这样的话下面再减一正好是最后一位元素}QElemSet q=deque->data[--deque->rear];return q;
}
34.先序创建 统计二叉树中具有度为1的结点数目
创建二叉树时记得创建的是每一个节点,和链表不同,这个是通过递归把左右子树的节点地址保存在该节点中实现的。
//头文件包含
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
#include <string>
#include <iostream>
using namespace std;
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define INFEASIBLE -2
#define NULL 0
typedef int Status;//二叉链表存储结构定义
typedef char TElemType;
typedef struct BiTNode{TElemType data;struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;//创建二叉树各结点,输入零代表创建空树
//采用递归的思想创建
//递归边界:空树如何创建呢:直接输入0;
//递归关系:非空树的创建问题,可以归结为先创建根节点,输入其数据域值;再创建左子树;最后创建右子树。左右子树递归即可完成创建!
int i=0;
Status CreateBiTree(BiTree &T,string s)
{TElemType e;if(!s[i])return OK;if(s[i]=='*'){T=NULL;i++;}else{T=(BiTree)malloc(sizeof(BiTNode));if(!T)exit(OVERFLOW);T->data=s[i++];CreateBiTree(T->lchild,s);CreateBiTree(T->rchild,s);}return OK;
}
int PreOrder(BiTNode* root)
{if(!root)return 0;else{//看清题目中让求的是度为1的,所以这样写
// return 1+PreOrder(root->lchild)+PreOrder(root->rchild);if((!root->lchild&&root->rchild)||(root->lchild&&!root->rchild))return 1+PreOrder(root->lchild)+PreOrder(root->rchild);elsereturn PreOrder(root->lchild)+PreOrder(root->rchild);}}
int main() {string s;BiTree B;while(cin>>s) {if(CreateBiTree(B,s)){i=0;int num=PreOrder(B);cout<<"num: "<<num<<endl;}}return 0;
}