二叉树

来源:互联网 发布:js获取复选框的值 编辑:程序博客网 时间:2024/06/05 16:47

之前已经介绍了二叉树的四种遍历(如果不熟悉请戳我),下面介绍一些二叉树的建立方式。首先需要明确的是,由于二叉树的定义是递归的,所以用递归的思想建立二叉树是很自然的想法。

1. 交互式问答方式

这种方式是最直接的方式,就是先询问用户根节点是谁,然后每次都询问用户某个节点的左孩子是谁,右孩子是谁。代码如下(其中字符'#'代表空节点):

复制代码
#include <cstdio>#include <cstdlib>using namespace std;typedef struct BTNode *Position;typedef Position BTree;struct BTNode{    char data;    Position lChild, rChild;};BTree CreateBTree(BTree bt, bool isRoot){    char ch;    if (isRoot)        printf("Root: ");    fflush(stdin);         /* 清空缓存区 */    scanf("%c", &ch);    fflush(stdin);    if (ch != '#')    {        isRoot = false;        bt = new BTNode;        bt->data = ch;          bt->lChild = NULL;        bt->rChild = NULL;        printf("%c's left child is: ", bt->data);        bt->lChild = CreateBTree(bt->lChild, isRoot);        printf("%c's right child is: ", bt->data);        bt->rChild = CreateBTree(bt->rChild, isRoot);    }    return bt;}int main(){    BTree bt;    bt = CreateBTree(bt, true);    LevelOrderTraversal(bt);        /* 层序遍历 */    return 0;}
复制代码

2. 根据先序序列

例如输入序列ABDH##I##E##CF#J##G##(#表示空),则会建立如下图所示的二叉树

思路和第一种方式很相似,只是代码实现细节有一点区别,这里给出创建函数

复制代码
BTree CreateBTree(){    BTree bt = NULL;    char ch;    scanf("%c", &ch);    if (ch != '#')    {        bt = new BTNode;        bt->data = ch;        bt->lChild = CreateBTree();        bt->rChild = CreateBTree();    }    return bt;}
复制代码

3. 根据中序序列和后序序列

和方式二不同的是,这里的序列不会给出空节点的表示,所以如果只给出先序序列,中序序列,后序序列中的一种,不能唯一确定一棵二叉树。但是如果给出中序序列和后序序列或者先序序列和中序序列就可以唯一确定一棵树。根据三种遍历方式的特点,我们可以利用先序序列或后序序列确定根节点,可以利用中序序列确定左右孩子。

由后序序列“左子树->右子树->根节点”性质可知后序序列的最后一个一定为这棵树的根节点,而又根据中序序列“左子树->根节点->右子树”的性质,由后序序列得到的根节点可以将中序序列分为左子树中序序列和右子树中序序列。然后根据序列的个数相同,可以将后序序列分为左子树后序序列和右子树后序序列。依次递归的进行,直到序列长度为空递归返回。同理,根据先序序列的“根节点->左子树->右子树”性质可得先序序列的第一个一定为这棵树的根节点,之后与上述类似。

例如:一棵二叉树的中序序列为:ABCEFGHD,后序序列为: ABFHGEDC。建立的二叉树如下图:

代码如下:

复制代码
/*通过中序序列和后序序列建树,然后先序遍历输出输入(第一行为中序,第二行为后序):ABCEFGHDABFHGEDC输出:CBADEGFH
*/#include <cstdio>#include <cstdlib>using namespace std;const int N = 1010;typedef struct BTNode *Position;typedef Position BTree;struct BTNode{ char data; Position lChild, rChild;};BTree CreateBTree(char inOd[], char postOd[], int n);void PreOrder(BTree bt);int main(){ char inOd[N], postOd[N]; /* 中序序列与后序序列 */ int n = 0; char ch; while ((ch = getchar()) && ch != '\n') inOd[n++] = ch; n = 0; while ((ch = getchar()) && ch != '\n') postOd[n++] = ch; BTree bt = CreateBTree(inOd, postOd, n); PreOrder(bt); printf("\n"); return 0;}BTree CreateBTree(char inOd[], char postOd[], int n){ if (n == 0) return NULL; BTree btRoot = new BTNode; btRoot->data = postOd[n-1]; //后序序列最后一个元素一定是根节点 char lInOd[N], rInOd[N]; char lPostOd[N], rPostOd[N]; int n1, n2; n1 = n2 = 0; //根据根节点将中序序列分为左子树和右子树 for (int i = 0; i < n; i++) { if (i <= n1 && inOd[i] != btRoot->data) lInOd[n1++] = inOd[i]; else if (inOd[i] != postOd[n-1]) rInOd[n2++] = inOd[i]; } //根据一个树的后序序列的长度等于中序序列且后序遍历是先左子树再右子树 //将后序序列分为左子树和右子树 int m1, m2; m1 = m2 = 0; for (int i = 0; i < n-1; i++) { if (i < n1) lPostOd[m1++] = postOd[i]; else rPostOd[m2++] = postOd[i]; } btRoot->lChild = CreateBTree(lInOd, lPostOd, n1); btRoot->rChild = CreateBTree(rInOd, rPostOd, n2); return btRoot;}void PreOrder(BTree bt){ if (bt != NULL) { printf("%c", bt->data); PreOrder(bt->lChild); PreOrder(bt->rChild); }}
复制代码