复习一下二叉树
二叉树的叶子结点总是比双分支结点多一个。
满二叉树:如果有H层,则总结点个数为2H(次方)-1,每一层有2H-1(次方)个结点。
二叉树的创建
结点信息
typedef struct node{
int data; // 存放此结点的值
struct node * left; // 指向此结点的左子女
struct node * right; // 指向此结点的右子女
}BTNode;
二叉树的非递归先序遍历
分析:
- 由于先序遍历的顺序是根、左、右,所以步骤是:先输出根结点的值,然后根结点变为左结点,但是这时如果不保存右结点的值,就会导致右边丢失再也找不回来,所以需要存储。
- 由于这些结点是先进后出,后进先出,所以用栈来存储。
- 也需要在栈中存储左子女,因为左子女出去了,就知道现在该它的右子女了。
- 栈中存储:先存右子女,再存左子女,根提前放入栈中。
算法描述:
- 创建栈:
BTNode ** s; // 声明一个栈
s = (BTNode **) malloc((N+1)*sizeof(BTNode *));// 创建栈
int top = -1; // 栈顶指针 - 初始化:
s[++top] = root; // 根结点入队 - 实现:
while(栈不空){
p = 出栈元素;
输出此结点的值;
有右子女,右子女入栈;
有左子女,左子女入栈;
}
代码:
# include <stdio.h>
# include <stdlib.h>
# define N 9
//定义结构体:结点信息
typedef struct node{
int data; // 存放此结点的值
struct node * left; // 指向此结点的左子女
struct node * right; // 指向此结点的右子女
}BTNode; // 结构体名为BTNode
BTNode * CreatTree(int[],int);
void Forder(BTNode * root);
void InOrder(BTNode * root);
void LastOrder(BTNode * root);
void Forder2(BTNode * root);
int main(void){
BTNode * root; // 存放此二叉树的根结点
int A[8] = {3,2,5,8,4,7,6,9}; // 这里直接固定了建立二叉树的值
root = CreatTree(A, 8); // 调用创建二叉树的函数
printf("\n");
Forder(root); printf("\n"); // 递归先序遍历二叉树
InOrder(root); printf("\n"); // 递归中序遍历二叉树,可得到升序序列
LastOrder(root); printf("\n"); // 递归后序遍历二叉树
Forder2(root); printf("\n"); // 非递归先序遍历二叉树
return 0;
}
BTNode * CreatTree(int A[], int n){
int i; // 用于下面的循环变量
BTNode * p, * root; // 当前刚刚创建的结点
// 创建根结点
root = (BTNode *) malloc (sizeof(BTNode));
root->data = A[0];
root->left = root->right = NULL;
// 创建其他结点
for(i = 1; i < n; i++){
BTNode * cp, * pa; //cp,pa用来找刚创建的结点刚放在哪里,pa指向此结点的双亲结点,具体如下
// 创建新结点
p = (BTNode *)malloc(sizeof(BTNode));
p->data = A[i];
p->left = p->right = NULL;
// 找此结点该放在什么位置
cp = root;
while(cp){
pa = cp; // 每次pa都先保存cp的位置,cp再往下找,直到叶子结点
if(cp->data > p->data) cp = cp->left; // 值比根小,向左
else cp = cp->right; // 反之,向右
}
if(pa->data > p->data){ // 判断挂在左还是右
pa->left = p;
}else{
pa->right = p;
}
}
return root;
}
/*
malloc:
函数原型:void *malloc(unsigned int num_bytes);
分配长度为num_bytes字节的内存块
作用:当无法知道内存具体的位置时,想要绑定真正的内存空间,就要用到malloc()函数
同时也利用了内存的碎片内存*/
// 递归先序遍历二叉树 (根左右)
void Forder(BTNode * root){
if(root){
printf("%5d",root->data);
Forder(root->left);
Forder(root->right);
}
}
// 递归中序遍历二叉树 (左根右)
void InOrder(BTNode * root){
if(root){
InOrder(root->left);
printf("%5d",root->data);
InOrder(root->right);
}
}
// 递归后序遍历二叉树 (左右根)
void LastOrder(BTNode * root){
if(root){
LastOrder(root->left);
LastOrder(root->right);
printf("%5d",root->data);
}
}
// 非递归先序遍历
void Forder2(BTNode * root){
BTNode ** s; // 声明一个栈
int top = -1; // 栈顶指针
BTNode * p; // 指向当前结点
// 创建栈
s = (BTNode **) malloc((N+1)*sizeof(BTNode *));
// 初始化栈
s[++top] = root; // 根结点入队
// 非递归先序遍历
while(top != -1){ // 队不空
p = s[top--]; // 从栈顶取出一个结点输出
printf("%5d",p->data); //输出结点
if(p->right) s[++top] = p->right; // 如果右节点不为空,入队
if(p->left) s[++top] = p->left; // 如果左节点不为空,入队
}
free(s); // 释放栈,因为malloc分配的空间需要自己释放。
}
二叉树的非递归中序遍历
基本思想:根结点先入栈从根结点一直向左走,走的过程入栈,直到左子树为空则访问。然后退栈,查看是否有右指针,若有则以其为根再找最左下结点,否则访问
二叉树的非递归后序遍历
基本思想:把先序的输出放在后面,刚开始初始化时入栈三个,一个是根,一个是根的右,一个是根的左。