数据结构之顺序二叉树

来源:互联网 发布:mac 映射网络驱动器 编辑:程序博客网 时间:2024/06/05 14:21

一.引入

        二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且用结点的存储位置(下标)表示结点之间的逻辑关系——父子关系。

        由于二叉树本身不具有顺序关系,所以二叉树的顺序存储结构要解决的关键问题时如何利用数组下标来反映结点之间的逻辑关系。由二叉树的性质可知,完全二叉树中结点的层序编号可以唯一地反映结点之间的逻辑关系,对于一般的二叉树,可以增添一些并不存在的空结点,使之成为一棵完全二叉树的形式,然后再用一维数组顺序存储。具体步骤如下:

       (1)将二叉树按完全二叉树编号。根结点的编号为 1 ,若某结点 i 有左孩子,则其左孩子的编号为 2i ;若某结点 i 有右孩子,则其右孩子的编号为 2i+1 ;

       (2)将二叉树中的结点以编号顺序存储到一维数组中。注意,C++语言的数组下标从 0 开始,因此,编号为 i 的结点存储到下标为 i-1 的位置。


注:而本程序为了操作上的方便,将结点从数组下标 1 开始存储。


二.算法设计

SeqBinaryTree.h

#ifndef SRC_SEQBINARYTREE_H_#define SRC_SEQBINARYTREE_H_#include <string>using namespace std;class SeqBinaryTree{public:SeqBinaryTree();//构造器virtual ~SeqBinaryTree();//析构函数void leverOrder();//层序遍历void getParentAndChild();//输出各个结点和其双亲、孩子void getLeaves();//输出叶子private:const static int MAX_LENGTH = 100;//静态数组的最大长度string array[MAX_LENGTH];//存放结点int valueIndex[MAX_LENGTH];//存放有数据的结点的角标int num = 0;//记录有数据的结点个数bool hasRelate(int index);//检查结点是否有亲属(双亲、孩子)};#endif

三.详细设计(C++)

SeqBinaryTree.cpp

#include "SeqBinaryTree.h"#include <string>#include <iostream>using namespace std;/* * 构造器: * 1.初始化静态数组,使其被赋值为 “#” * 2.定义一个 string 类型的变量 value ,用来记录用户输入的数据 * 3.循环:当输入 “!” 时结束 *   ①.提示用户输入结点数据 *   ②.用 value 记录输入的数据 *   ③.若输入 “!” 则跳出循环 *   ④.把 value 存储在角标为 i 的数组 array 里(i 从 1 开始) *   ⑤.若输入不为 “#” ,表示该结点真正有数据,则 *     ①.把该结点的角标存储在 valueIndex 数组里 *     ②.记录真正有数据的结点的个数 */SeqBinaryTree::SeqBinaryTree(){for(int i = 0;i < MAX_LENGTH;i++){array[i] = "#";}string value;for(int i = 1,j = -1;;i++){cout<<"输入结点数据(“!”结束):";cin>>value;if(value == "!"){break;}array[i] = value;if(value != "#"){valueIndex[++j] = i;num++;}}}/* * 析构函数: * 空的 */SeqBinaryTree::~SeqBinaryTree(){}/* * 层序遍历: * 从 valueIndex 数组中获取真正有数据的结点的角标,依次输出 array 数组 */void SeqBinaryTree::leverOrder(){for(int i = 0;i < num;i++){cout<<array[valueIndex[i]]<<" ";}}/* * 输出各个结点和其双亲、孩子: * 循环: * 1.输出真正有数据的结点 * 2.检查当前结点是否有双亲:当前结点 i 的双亲为 i/2(i >= 1) *   若角标为 valueIndex[i]/2 的 array 不为 “#” ,表示当前结点有双亲,则输出双亲的数据 *   否则,输出无 * 3.检查当前结点是否有左孩子:当前结点 i 的左孩子为 2i *   若角标为 valueIndex[i]*2 的 array 不为 “#” ,表示当前结点有左孩子,则输出左孩子的数据 *   否则,输出无 * 4.检查当前结点是否有右孩子:当前结点 i 的右孩子为 2i+1 *   若角标为 valueIndex[i]*2+1 的 array 不为 “#” ,表示当前结点有右孩子,则输出右孩子的数据 *   否则,输出无 */void SeqBinaryTree::getParentAndChild(){for(int i = 0;i < num;i++){cout<<"结点"<<array[valueIndex[i]]<<":"<<endl;cout<<"双亲为:";if(hasRelate(valueIndex[i]/2)){cout<<array[valueIndex[i]/2]<<endl;}else{cout<<"无"<<endl;}cout<<"左孩子为:";if(hasRelate(valueIndex[i]*2)){cout<<array[valueIndex[i]*2]<<endl;}else{cout<<"无"<<endl;}cout<<"右孩子为:";if(hasRelate(valueIndex[i]*2+1)){cout<<array[valueIndex[i]*2+1]<<endl;}else{cout<<"无"<<endl;}cout<<endl;}}/* * 输出叶子: * 循环: * 若当前结点的孩子数据都为 “#” ,表示当前结点为叶子,则输出当前结点数据 */void SeqBinaryTree::getLeaves(){for(int i = 0;i < num;i++){if(!hasRelate(valueIndex[i]*2) & !hasRelate(valueIndex[i]*2+1)){cout<<array[valueIndex[i]]<<" ";}}}/* * 检查结点是否有亲属(双亲、孩子): * 若角标为 index 的 array 数据不为 “#” ,表示其有亲属,返回 true ,否则返回 false */bool SeqBinaryTree::hasRelate(int index){return array[index] != "#" ? true : false;}

四.测试

TestSeqBinaryTree.cpp

#include "SeqBinaryTree.h"//#include "SeqBinaryTree.cpp"#include <iostream>using namespace std;int main(int argc, char **argv){cout<<"创建对象:"<<endl;SeqBinaryTree seqBinaryTree;cout<<endl;cout<<"层序输出:"<<endl;seqBinaryTree.leverOrder();cout<<endl<<endl;cout<<"各个结点和其双亲、孩子的情况:"<<endl;seqBinaryTree.getParentAndChild();cout<<"叶子的情况:";seqBinaryTree.getLeaves();cout<<endl;return 0;}

五.运行结果














六.分析

        显然,这种存储方法会造成存储空间的浪费,最坏的情况是右斜树。事实上,二叉树的顺序存储结构一般仅适合存储完全二叉树。

原创粉丝点击