二叉树和二叉排序树啥啥的在上数据结构这门课时就没搞懂,时隔两年再看时突然莫名顿悟了一些,特写此心得记录一下,如果有什么地方理解出错了,请留言纠正,谢谢。
二叉排序树是一种特殊的二叉排序树,满足如下条件:对于树上任意一个结点,其上的数值必大于等于其左子树上任意结点的数值,必小于等于其右子树上任意结点的数值。
二叉树的插入:1、若目前树为空,则插入第一个数,作为根节点。2、目前树不为空,则从根节点开始比较,若小于(等于)根结点,且根节点左孩子为空,则插入第二个数作为根节点的左孩子;若不为空,则与根节点的左孩子比较。若大于(等于)根结点,且根节点右孩子为空,则插入第二个数作为根节点的右孩子;若不为空,则与根节点的右孩子比较。3、每插入一个数都是从根节点开始比较,重复2的步骤直到插入结束。(括号中的等于根据不同题目要求具体看是否要包括等于的情况)
由于各个数字的插入顺序不同,所得的二叉排序树的形态也很可能不同。但是,所有的二叉排序树的中序遍历都是一个递增的序列,通过建立二叉排序树就能对原无序序列进行排序,并实现动态维护。
二叉树的遍历:遍历分为三种,先序遍历、中序遍历、后序遍历。先序遍历是按照根左右的顺序,中序是左根右,后序是左右根,个人感觉看代码更容易理解遍历的实现过程,语文不好难以描述┑( ̄Д  ̄)┍
借助例子来看看吧(借用九度1201题二叉排序树)
-
题目描述:
-
输入一系列整数,建立二叉排序数,并进行前序,中序,后序遍历。
-
输入:
-
输入第一行包括一个整数n(1<=n<=100)。
接下来的一行包括n个整数。
-
输出:
-
可能有多组测试数据,对于每组数据,将题目所给数据建立一个二叉排序树,并对二叉排序树进行前序、中序和后序遍历。
每种遍历结果输出一行。每行最后一个数据之后有一个空格。
-
样例输入:
-
5 1 6 5 9 8
-
样例输出:
-
1 6 5 9 8 1 5 6 8 9 5 8 9 6 1
-
提示:
-
输入中可能有重复元素,但是输出的二叉树遍历序列中重复元素不用输出。
-
#include<stdio.h> #include<stdlib.h> #include<string.h> struct node //定义节点的结构体 { node *lchild; //左孩子 node *rchild; //右孩子 int c; //节点的数值 }tree[201]; /*数据采用全局变量节省了函数间互相传参的麻烦,不过也要慎用*/ int loc; //loc表示申请了空间的节点的个数 node *t; //构建的二叉排序树 node *ret; //当前申请空间的节点 node* create() //结点的空间申请函数,返回该节点对应的结构体指针 { tree[loc].lchild = tree[loc].rchild = NULL; //初始化左右子树为空 return &tree[loc++]; //返回指针后,loc再++ } void build(node *k,int s) { if (s < k->c) //从根节点开始比较 { if (k->lchild == NULL) //如果比较的节点的左孩子为空 { ret = create(); //则创建新节点,并作为该节点的左孩子 ret->c = s; k->lchild = ret; } else //如果左孩子不为空,则递归访问节点的左孩子 { build(k->lchild,s); } } else if (s > k->c) //大于的情况与小于相似,就不赘述了 { if (k->rchild == NULL) { ret = create(); ret->c = s; k->rchild = ret; } else { build(k->rchild,s); } } } void inorder(node *t) //先序遍历 { printf("%d ", t->c); //遍历该结点,输出其字符信息 if (t->lchild != NULL) //若左子树不为空 { inorder(t->lchild); //递归遍历其左子树 } if (t->rchild != NULL) //若右子树不为空 { inorder(t->rchild); //递归遍历其右子树 } } void midorder(node *t) //中序遍历 { if (t->lchild != NULL) //若左子树不为空 { midorder(t->lchild); //递归遍历其左子树 } printf("%d ", t->c); //遍历该结点,输出其字符信息 if (t->rchild != NULL) //若右子树不为空 { midorder(t->rchild); //递归遍历其右子树 } } void postorder(node *t) //后序遍历 { if (t->lchild != NULL) //若左子树不为空 { postorder(t->lchild); //递归遍历其左子树 } if (t->rchild != NULL) //若右子树不为空 { postorder(t->rchild); //递归遍历其右子树 } printf("%d ", t->c); //遍历该结点,输出其字符信息 } int main() { int i,n,arr[201]; //n为节点个数,arr为所有节点数值的数值,也可采用动态数组 while (scanf("%d",&n)!=EOF) //因为输入可能包含多组数据,重复读入n,直到n为文件结束符 { for (i = 0; i < n; i++) scanf("%d", &arr[i]); //读入节点的数值 loc = 0; t = create(); //创建根节点 t->c = arr[0]; for (i = 1; i < n; i++) //从第二个数值开始插入 build(t,arr[i]); inorder(t); //先序遍历 printf("\n"); midorder(t); //中序遍历 printf("\n"); postorder(t); //后序遍历 printf("\n"); } return 0; }
由于数字插入顺序不同会导致二叉排序树的不同,但这种情况下的中序遍历是相同的,所以需要中序遍历+先序遍历 或 中序遍历+后序遍历才能确定唯一的二叉树。
-