数据结构与算法备忘:根据层次顺序存储结构构建二叉树

在存储满二叉树或近似满二叉树时,按节点层次顺序存储是个不错的主意,我们从根节点开始,逐层由左到右扫描各个节点,依次将节点数据存放到指定的数组中,如果偶尔遇到空的子节点,就用特殊符号来表示。

这个树结构已接近满二叉树了,如果使用按层次顺序存储,将会更简单,更节省空间。按照上面的方法,这棵树所对应的存储结构应该是:

[‘A‘, ‘B‘, ‘E‘, ‘C‘, ‘D‘, ‘#‘, ‘F‘]

其中空的子节点,我们使用#号来占位。

根据这个存储结构,我们就可以构建出一棵二叉树,还原它本来的面目。

思路如下:

  1. 我们知道,根节点起始位置array[0],节点个数为1,第二层起始位置array[1],节点个数为2,每一层起始位置的索引都是前面节点的总个数,我们需要记录父层起始位置和当前层的起始位置。
  2. 根据满二叉树的结构,可以得出当前层节点的个数:pow(2, level -1),其中level即为当前层数,从1开始。
  3. 遍历当前层的节点,规则是:每遍历两个节点,父层遍历一个,在遍历过程中,创建相应的节点对象,并与父节点进行关联。
  4. 遍历完成后,当前层将成为下一轮的父层,重新计算下一层的起始位置和节点个数。然后开始下一轮。

上面提到这种存储顺序适用于满二叉树或接近满二叉树的情况,所以这里我们只考虑极少数的空叶子节点,对于最后一层空的叶子节点,如果它们是连续排在最后面的,则也可以省略,以节省存储空间。

下面是实现代码:

JS版:

//二叉树节点结构
function BinTreeNode(data) {
  this.data = data;
  this.leftChild = null;
  this.rightChild = null;
}

//根据顺序存储序列创建二叉树
function createBinTreeByArray(array) {

  //初始化树的层次,每层存储pow(2, currLevel - 1)个节点数据
  var currLevel = 1;

  //初始化当前节点层和父层起始位置
  var currLevelBegin = 0,
      parentLevelBegin = 0;

  //节点数组,用于放置新建的节点
  var nodeArray = [];

  //循环遍历每一层
  while (currLevelBegin < array.length) {

    //每一层的节点数量
    var levelNumber = Math.pow(2, currLevel - 1);

    //记录父层的step,初始值0
    var parentStep = 0;

    //遍历当前节点层每个节点数据
    for (var step = 0; step < levelNumber; step++) {
      //计算在数组中的索引
      var index = currLevelBegin + step;

      if (index >= array.length) break;

      var node = null;

      //创建节点对象,并放进节点数组中
      if (array[index] !== ‘#‘) {
        node = new BinTreeNode(array[index]);
        nodeArray.push(node);
      }

      //如果不是根节点层,则需要与父节点做关联
      if (currLevelBegin > 0) {

        //获取父节点
        var parentNode = nodeArray[parentLevelBegin + parentStep];

        //step是从0开始的,如果是偶数则成为左子节点,奇数则成为右子节点
        if (step % 2 === 0) {
          parentNode.leftChild = node;
        } else {
          parentNode.rightChild = node;

          //父层的step递增一位,指向下一个
          parentStep++;
        }

      }

    }

    //更新父层和当前层的起始位置
    parentLevelBegin = currLevelBegin;

    currLevelBegin += levelNumber;

    //层数加1
    currLevel++;
  }

  //返回根节点
  return nodeArray[0];
}

//前序遍历
function preOrderTraverse(node, orderArray) {
  if (node) {
    orderArray.push(node.data);
    preOrderTraverse(node.leftChild, orderArray);
    preOrderTraverse(node.rightChild, orderArray);
  }
}

//中序遍历
function inOrderTraverse(node, orderArray) {
  if (node) {
    inOrderTraverse(node.leftChild, orderArray);
    orderArray.push(node.data);
    inOrderTraverse(node.rightChild, orderArray);
  }
}

//后序遍历
function postOrderTraverse(node, orderArray) {
  if (node) {
    postOrderTraverse(node.leftChild, orderArray);
    postOrderTraverse(node.rightChild, orderArray);
    orderArray.push(node.data);
  }
}

var array = [‘A‘, ‘B‘, ‘E‘, ‘C‘, ‘D‘, ‘#‘, ‘F‘];

//根据顺序存储序列创建二叉树
var binTree = createBinTreeByArray(array);

//用于存放节点遍历序列
var orderArray = [];

//前序遍历
preOrderTraverse(binTree, orderArray);
console.log(‘pre order: ‘, orderArray.join(‘ ‘));

//清空遍历序列数组
orderArray.length = 0;

//后序遍历
inOrderTraverse(binTree, orderArray);
console.log(‘in order: ‘, orderArray.join(‘ ‘));

orderArray.length = 0;

//后序遍历
postOrderTraverse(binTree, orderArray);
console.log(‘post order: ‘, orderArray.join(‘ ‘));

Java版:

//BinTreeNode.java

package algorithm;

//二叉树节点结构
public class BinTreeNode {
    private char data;
    private BinTreeNode leftChild;
    private BinTreeNode rightChild;

    public BinTreeNode(char data) {
        this.data = data;
    }

    public char getData() {
        return data;
    }

    public void setData(char data) {
        this.data = data;
    }

    public BinTreeNode getLeftChild() {
        return leftChild;
    }

    public void setLeftChild(BinTreeNode leftChild) {
        this.leftChild = leftChild;
    }

    public BinTreeNode getRightChild() {
        return rightChild;
    }

    public void setRightChild(BinTreeNode rightChild) {
        this.rightChild = rightChild;
    }
}

//BinTreeCreator.java

package algorithm;

public class BinTreeCreator {

    //根据顺序存储序列创建二叉树
    public static BinTreeNode createBinTreeByArray(char[] array) {

        int currLevel = 1;

        int currLevelBegin = 0, parentLevelBegin = 0;

        BinTreeNode[] nodeArray = new BinTreeNode[array.length];

        while (currLevelBegin < array.length) {

            int levelNumber = (int) Math.pow(2, currLevel - 1);

            int parentStep = 0;

            for (int step = 0; step < levelNumber; step++) {

                int index = currLevelBegin + step;

                if (index >= array.length) break;

                BinTreeNode node = null;

                if (array[index] != ‘#‘) {
                    node = new BinTreeNode(array[index]);
                    nodeArray[index] = node;
                }

                if (currLevelBegin > 0) {

                    BinTreeNode parentNode = nodeArray[parentLevelBegin + parentStep];

                    if (step % 2 == 0) {
                        parentNode.setLeftChild(node);
                    } else {
                        parentNode.setRightChild(node);

                        parentStep++;
                    }
                }
            }

            parentLevelBegin = currLevelBegin;

            currLevelBegin += levelNumber;

            currLevel++;
        }

        return nodeArray[0];
    }

    //前序遍历
    public static void preOrderTraverse(BinTreeNode node) {
        if (node != null) {
            System.out.print(node.getData());
            preOrderTraverse(node.getLeftChild());
            preOrderTraverse(node.getRightChild());
        }
    }

    //中序遍历
    public static void inOrderTraverse(BinTreeNode node) {
        if (node != null) {
            inOrderTraverse(node.getLeftChild());
            System.out.print(node.getData());
            inOrderTraverse(node.getRightChild());
        }
    }

    //后序遍历
    public static void postOrderTraverse(BinTreeNode node) {
        if (node != null) {
            postOrderTraverse(node.getLeftChild());
            postOrderTraverse(node.getRightChild());
            System.out.print(node.getData());
        }
    }

    public static void main(String[] args) {

        char[] array = {‘A‘, ‘B‘, ‘E‘, ‘C‘, ‘D‘, ‘#‘, ‘F‘};

        BinTreeNode rootNode = BinTreeCreator.createBinTreeByArray(array);

        System.out.print("pre order: ");
        BinTreeCreator.preOrderTraverse(rootNode);

        System.out.print(System.lineSeparator() + "in order: ");
        BinTreeCreator0.inOrderTraverse(rootNode);

        System.out.print(System.lineSeparator() + "post order: ");
        BinTreeCreator.postOrderTraverse(rootNode);
    }
}

C语言版:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef struct node {
    char data;
    struct node *lchild, *rchild;
} BinTreeNode;

BinTreeNode * createBinTreeByArray(char *array, int size);
void preOrderTraverse(BinTreeNode *node);
void inOrderTraverse(BinTreeNode *node);
void postOrderTraverse(BinTreeNode *node);

int main(int argc, const char * argv[]) {

    char array[] = {‘A‘, ‘B‘, ‘E‘, ‘C‘, ‘D‘, ‘#‘, ‘F‘};

    BinTreeNode *rootNode = createBinTreeByArray(array, sizeof(array));

    printf("pre order: ");
    preOrderTraverse(rootNode);
    printf("\nin order: ");
    inOrderTraverse(rootNode);
    printf("\npost order: ");
    postOrderTraverse(rootNode);

    return 0;
}

//根据顺序存储序列创建二叉树
BinTreeNode * createBinTreeByArray(char *array, int size) {

    int currLevel = 1;

    int currLevelBegin = 0;
    int parentLevelBegin = 0;

    BinTreeNode **nodeArray = (BinTreeNode **) malloc(sizeof(BinTreeNode *) * size);

    while (currLevelBegin < size) {
        int levelNumber = pow(2, currLevel - 1);

        int parentStep = 0;

        for (int step = 0; step < levelNumber; step++) {
            int index = currLevelBegin + step;

            if (index >= size) break;

            BinTreeNode *node = NULL;

            if (array[index] != ‘#‘) {
                node = (BinTreeNode *) malloc(sizeof(BinTreeNode));
                node->data = array[index];
                node->lchild = NULL;
                node->rchild = NULL;

                nodeArray[index] = node;
            }

            if (currLevelBegin > 0) {
                BinTreeNode *parentNode = nodeArray[parentLevelBegin + parentStep];

                if (step % 2 == 0) {
                    parentNode->lchild = node;
                } else {
                    parentNode->rchild = node;

                    parentStep++;
                }
            }
        }

        parentLevelBegin = currLevelBegin;

        currLevelBegin += levelNumber;

        currLevel++;
    }

    free(nodeArray);

    return nodeArray[0];
}

//前序遍历
void preOrderTraverse(BinTreeNode *node) {
    if (node != NULL) {
        printf("%c", node->data);

        preOrderTraverse(node->lchild);

        preOrderTraverse(node->rchild);
    }
}

//中序遍历
void inOrderTraverse(BinTreeNode *node) {
    if (node != NULL) {
        inOrderTraverse(node->lchild);

        printf("%c", node->data);

        inOrderTraverse(node->rchild);
    }
}

//后序遍历
void postOrderTraverse(BinTreeNode *node) {
    if (node != NULL) {
        postOrderTraverse(node->lchild);

        postOrderTraverse(node->rchild);

        printf("%c", node->data);
    }
}
时间: 2024-08-28 06:38:58

数据结构与算法备忘:根据层次顺序存储结构构建二叉树的相关文章

图论类算法备忘

1. 图的定义: Graph = (V, E)表示图由顶点集和边集组成 2. 图的存储结构:常用的主要有 邻接矩阵和邻接表, 还有十字链表和邻接多重表等 邻接矩阵, 如 graph[i][j] = cost , 表示顶点i到顶点j的距离是cost 邻接表 数据结构表示 typedef struct arc { int m_adjVertex;// 邻接顶点的索引 int m_weight;    // 权值 struct arc *nextArc; }Arc; typedef struct ve

数据结构(十五)串的顺序存储结构(顺序串)

一.串的定义:串(String)是由零个或多个字符组成的有限序列,又名叫字符串. 二.串中的字符数目n称为串的长度,零个字符的串称为空串(null string),它的长度为零.子串在主串中的位置就是子串的第一个字符在主串中的序号. 三.串的大小:首先比较每个字符对应的ASCII码,然后比较长度n. 四.串中关注更多的是查找子串位置.得到指定位置子串.替换子串等操作. 五.串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的.按照预定义的大小,为每个定义的串变量分配一个固定长度的存储

利用层次遍历原理构建二叉树

层次遍历构建二叉树: 1.定义二叉树节点: 1 function TreeNode(val){ 2 this.val = val; 3 this.left = this.right = null; 4 } 2.层次遍历构建二叉树: 1 function createTree(arr){ 2 if(!arr||!arr.length)return null; 3 var root = new TreeNode(arr.shift()); 4 var list = [root]; 5 while(a

数据结构和算法基础之队列的顺序存储

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { /// <summary> /// 顺序队列 /// </summary> public class OrderQueue<T> { public T[] DataArry; /

数据结构笔记01:线性表之顺序存储结构(ArrayList)

一般使用数组(C语言中的数组采用顺序存储方式.即连续地址存储)来描述. 优点:在于随机访问元素. 缺点:插入和和删除的时候,需要移动大量的元素. c语言实现代码:ArrayList 1 // Test.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include <stdio.h> 6 #include "stdlib.h&quo

[手机按键备忘]常见的脚本结构思路的补充(强化了错误代码的处理部分个人向)

思路代码(还是以前的旧代码 并且只是思路代码 无法直接使用) //例子:遍历读取账号文件内容 并且具备记忆功能 自动从上次的位置开始 不是粗暴的执行一个删除一个账号的处理 而是把记忆写到脚本配置里面 //1.读取账号文件内容 //2.对账号文件做基础的判断和处理 文件是否存在 内容是否对 是否去掉了可能的Bom头和乱码 去掉空行等等 这里粗略的写一写 //3.获取账号文件内容转化为数组 账号文件内容数组 = file.ReadLines(账号文件路径) //4.读取脚本本身的配置 看看是否记录了

数据结构与算法题目集(中文) 6-8 求二叉树高度 (20分)

1 // #include <stdio.h> 2 // #include <stdlib.h> 3 4 // typedef char ElementType; 5 // typedef struct TNode *Position; 6 // typedef Position BinTree; 7 // struct TNode{ 8 // ElementType Data; 9 // BinTree Left; 10 // BinTree Right; 11 // }; 12

数据结构与算法(二叉树)

二叉树的存储结构 二叉树的存储可分为两种:顺序存储结构和链式存储结构. 1.      顺序存储结构 把一个满二叉树自上而下.从左到右顺序编号,依次存放在数组内,可得到图6.8(a)所示的结果.设满二叉树结点在数组中的索引号为i,那么有如下性质. (1) 如果i = 0,此结点为根结点,无双亲. (2) 如果i > 0,则其双亲结点为(i -1) / 2 .(注意,这里的除法是整除,结果中的小数部分会被舍弃.) (3) 结点i的左孩子为2i + 1,右孩子为2i + 2. (4) 如果i >

数据结构|-完全二叉树的顺序存储结构的实现

对于一个完全二叉树,假设它有n个结点,对结点进行从1开始编号,对任一结点i满足下面 它的双亲是结点 i/2 (除了i=1的情况) 左孩子是 2i 右孩子是 2i+1 如果2i>n 说明无左孩子 2i+1>n 说明无右孩子 一般的树来说是一对多的关系,使用顺序结构存储起来比较困难,但是二叉树是一种特殊的树,每个结点最多有两个子节点,并且子节点有左右之分,并且兄弟,父亲,孩子可以很方便的通过编号得到,所以我们使用顺序存储结构使用二叉树的存储. using System; using System.