二叉树的存储结构和遍历算法

1. 二叉树的存储结构

1.1 顺序存储结构

顺序存储一棵二叉树时,首先对该树中的每个结点进行编号,然后以各结点的编号为下标,把各结点的值对应存储到一个一位数组中。每个结点的编号与等深度的满二叉树中对应结点的编号相等,即树根结点的编号为1,接着按照从上到下和从左到右的次序,若一个结点的编号为i,则左、右孩子的编号分别为2i和2i+1。如图,各结点上方的数字就是该结点的编号。

假设分别采用一维数组data1和data2来顺序存储上图的两棵二叉树,则两数组中各元素的值如下图所示。

在二叉树的顺序存储结构中,各结点之间的关系是通过下标计算出来的,因此访问每一个结点的双亲和左、右孩子都非常方便。如对于编号为i的结点,其双亲结点的下标为⌊i/2⌋,若存在左孩子,则左孩子结点的下标为2i,若存在右孩子,则右孩子结点的下标为2i+1。

二叉树的顺序存储结构对于存储完全二叉树是合适的,它能够充分利用存储空间,但对于一般二叉树,特别是对于那些单支结点较多的二叉树来说是很不合适的,因为可能只有少数存储位置被利用,而多数或绝大多数的存储位置空间着。

1.2 链接存储结构

 在二叉树的链接存储中,通常采用的方法是,在每个结点中设置3个域:值域、左指针域和右指针域。其结点结构为:

链接存储的另一种方法是:在上面的结点结构中再增加一个parent指针域,用来指向其双亲结点。这种存储结构既便于查找孩子结点,也便于查找双亲结点,当然也带来存储空间的相应增加。

同单链表相同,二叉链表既可由独立分配的结点链接而成,也可由数组中的元素结点链接而成。

若采用独立结点,则结点类型可定义为:

1 struct BTreeNode {
2     ElemType data;
3     BTreeNode* left;
4     BTreeNode* right;       
5 };

若采用元素结点,则结点类型可定义为:

1 struct ABTreeNode {
2     ElemType data;
3     int left, right;
4 };

元素结点从下标为1的位置起使用,下标为0的位置的左指针域通常用来存储树根指针,右指针域通常用来存储空闲链表的表头指针,空闲链表由空闲结点的right域链接而成。

2. 二叉树遍历

二叉树遍历算法有:前序遍历、中序遍历、后序遍历和按层遍历。

若将跟结点、左子树和右子树分别用D、L和R表述,则前序遍历顺序为DLR,中序遍历顺序为LDR,后序遍历顺序为LRD。

对于上图二叉树,

前序遍历为:ABCDEFG

中序遍历为:CBDAEGF

后序遍历为:CDBGFEA

按层遍历为:ABECDFG

2.1 前序遍历算法

1 void PreOrder(BTreeNode* BT) {
2     if(BT != NULL) {
3         cout << BT->data << ' ';     //访问根结点
4         PreOrder(BT->left);          //前序遍历左子树
5         PreOrder(BT->right);         //前序遍历右子树
6     }
7 }

2.2 中序遍历算法

1 void InOrder(BTreeNode* BT) {
2     if(BT != NULL) {
3         InOrder(BT->left);          //中序遍历左子树
4         cout << BT->data << ' ';    //访问根结点
5         InOrder(BT->right);         //中序遍历右子树
6     }
7 }

2.3 后序遍历算法

1 void PostOrder(BTreeNode* BT) {
2     if(BT != NULL) {
3         PostOrder(BT->left);        //后序遍历左子树
4         PostOrder(BT->right);       //后序遍历右子树
5         cout << BT->data << ' ';    //访问根结点
6     }
7 }

 

猜你喜欢

转载自www.cnblogs.com/jim-blogs/p/9064986.html