前言:存储二叉树的关键是如何表示结点之间的逻辑关系,也就是双亲和孩子之间的关系。在具体应用中,可能要求从任一结点能直接访问到它的孩子。

一、二叉链表

  二叉树一般多采用二叉链表(binary linked list)存储,其基本思想是:令二叉树的每一个结点对应一个链表结点链表结点除了存放与二叉树结点有关的数据信息外,还要设置指示左右孩子的指针。二叉链表的结点结构如下图所示:

二叉树结点结构
lchild data rchild

其中,data为数据域,存放该结点的数据信息;

lchild为左指针域,存放指向左孩子的指针,当左孩子不存在时为空指针;

rchild为右指针域,存放指向右孩子的指针,当右孩子不存在时为空指针;

  可以用C++语言中的结构体类型描述二叉链表的结点,由于二叉链表的结点类型不确定,所以采用C++的模板机制。如下:

 // 二叉链表的节点
template<class T>
struct BiNode
{
T data; // 数据域
BiNode<T>*lchild, *rchild; // 左右指针域
};

 二、C++实现

  将二叉树的二叉链表存储结构用C++的类实现。为了避免类的调用者访问BiTree类的私有变量root,在构造函数、析构函数以及遍历函数中调用了相应的私有函数。

具体代码实现如下:

1、头文件“cirqueue.h”

此头文件为队列的类实现,层序遍历要用到队列,所以自己定义了一个队列。

 #pragma once
#include <iostream>
const int queueSize = ;
template<class T>
class queue
{
public:
....
T data[queueSize];
int front, rear;
....
};

2、头文件“bitree.h”

此头文件为二叉链表的类实现。

#pragma once
#include <iostream>
#include "cirqueue.h"
// 二叉链表的节点
template<class T>
struct BiNode
{
T data; // 数据域
BiNode<T>*lchild, *rchild; // 左右指针域
};
// 二叉链表类实现
template<class T>
class BiTree
{
public:
BiTree() { root = Creat(root); } // 构造函数,建立一颗二叉树
~BiTree() { Release(root); } // 析构函数,释放各节点的存储空间
void PreOrder() { PreOrder(root); } // 递归前序遍历二叉树
void InOrder() { InOrder(root); } // 递归中序遍历二叉树
void PostOrder() { PostOrder(root); } // 递归后序遍历二叉树
void LeverOrder(); // 层序遍历二叉树
private:
BiNode<T>* root; // 指向根节点的头节点
BiNode<T>* Creat(BiNode<T>* bt); // 构造函数调用
void Release(BiNode<T>* bt); // 析构函数调用
void PreOrder(BiNode<T>* bt); // 前序遍历函数调用
void InOrder(BiNode<T>* bt); // 中序遍历函数调用
void PostOrder(BiNode<T>* bt); // 后序遍历函数调用
}; template<class T>
inline void BiTree<T>::LeverOrder()
{
queue<BiNode<T>*> Q; // 定义一个队列
Q.front = Q.rear = -;  // 顺序队列
if (root == NULL)
return;
Q.data[++Q.rear] = root;  // 根指针入队
while (Q.front != Q.rear)
{
BiNode<T>* q = Q.data[++Q.front]; // 出队
cout << q->data;
if (q->lchild != NULL)
Q.data[++Q.rear] = q->lchild; // 左孩子入队
if (q->rchild != NULL)
Q.data[++Q.rear] = q->rchild; // 右孩子入队
} } template<class T>
inline BiNode<T>* BiTree<T>::Creat(BiNode<T>* bt)
{
T ch;
cin >> ch;                  // 输入结点的数据信息,假设为字符
if (ch == '#')                // 建立一棵空树
bt = NULL;
else
{
bt = new BiNode<T>;          // 生成一个结点,数据域为ch
bt->data = ch;
bt->lchild = Creat(bt->lchild);   // 递归建立左子树
bt->rchild = Creat(bt->rchild);   // 递归建立右子树
}
return bt;
} template<class T>
inline void BiTree<T>::Release(BiNode<T>* bt)
{
if (bt != NULL)
{
Release(bt->lchild);          // 释放左子树
Release(bt->rchild);          // 释放右子树
delete bt;                // 释放根节点
}
} template<class T>
inline void BiTree<T>::PreOrder(BiNode<T>* bt)
{
if (bt == NULL)              // 递归调用的结束条件
return;
cout << bt->data;             // 访问根节点bt的数据域
PreOrder(bt->lchild);           // 前序递归遍历bt的左子树
PreOrder(bt->rchild);           // 前序递归遍历bt的右子树
} template<class T>
inline void BiTree<T>::InOrder(BiNode<T>* bt)
{
if (bt == NULL)
return;
InOrder(bt->lchild);
cout << bt->data;
InOrder(bt->rchild);
} template<class T>
inline void BiTree<T>::PostOrder(BiNode<T>* bt)
{
if (bt == NULL)
return;
PostOrder(bt->lchild);
PostOrder(bt->rchild);
cout << bt->data;
}

说明:1、除了层序遍历,其他遍历均为递归算法。

   2、为什么层序遍历使用队列:在进行层序遍历时,对某一层的结点访问完后,再按照它们的访问次序对各个结点的左孩子和右孩子顺序访问,这样一层一层进行,先访问的结点其左右孩子也要先访问,这符合队列的操作特性,因此,在进行层序遍历时,可设置一个队列存放已访问的结点。

   3、构造函数对二叉树的特殊处理:将二叉树中每个结点的空指针引出一个虚结点,其值为一特定值,如‘#’,以标识其为空。

4、二叉链表属于动态内存分配,需要在析构函数中释放二叉链表的所有结点。在释放某结点时,该结点的左右都子树已经释放,所以应该采用后序遍历。

3、主函数

 #include"bitree.h"
using namespace std; int main()
{
BiTree<char>* bitree=new BiTree<char>(); // 创建一棵二叉树
bitree->PreOrder(); // 前序遍历
cout << endl;
bitree->InOrder(); // 中序遍历
cout << endl;
bitree->PostOrder(); // 后序遍历
cout << endl;
bitree->LeverOrder(); // 层序遍历
delete bitree; system("pause");
return ;
}

三、实例

  建立如下二叉树,并输出四种遍历的结果。

运行结果:

结果正确。

参考文献:

[1]王红梅, 胡明, 王涛. 数据结构(C++版)[M]. 北京:清华大学出版社。

马上元旦了,祝大家元旦快乐!!2017-12-29

二叉树的二叉链表存储结构及C++实现的更多相关文章

  1. 建立二叉树的二叉链表存储结构(严6.70)--------西工大noj

    #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct TreeNode ...

  2. C语言递归实现二叉树(二叉链表)的三种遍历和销毁操作(实验)

    今天写的是二叉树操作的实验,这个实验有三个部分: ①建立二叉树,采用二叉链表结构 ②先序.中序.后续遍历二叉树,输出节点值 ③销毁二叉树 二叉树的节点结构定义 typedef struct BiTNo ...

  3. 二叉树(二叉链表实现)JAVA代码

      publicclassTest{       publicstaticvoid main(String[] args){           char[] ch =newchar[]{'A','B ...

  4. 建立二叉树的二叉链表(严6.65)--------西工大noj

    需要注意的点:在创建二叉树的函数中,如果len1==len2==0,一定要把(*T)置为NULL然后退出循环 #include <stdio.h> #include <stdlib. ...

  5. C#实现二叉树--二叉链表结构

    二叉树的简单介绍 关于二叉树的介绍请看这里 : 二叉树的简单介绍 http://www.cnblogs.com/JiYF/p/7048785.html 二叉链表存储结构: 二叉树的链式存储结构是指,用 ...

  6. c使用二叉链表创建二叉树遇到的一些疑问和思考

    二叉链表存储二叉树 学习的时候参考的是<大话数据结构>,书中是这样定义的 typedef char TElemType; typedef struct BiTNode { TElemTyp ...

  7. 【开200数组解决二叉搜索树的建立、遍历】PAT-L3-016. 二叉搜索树的结构——不用链表来搞定二叉搜索树

    L3-016. 二叉搜索树的结构 二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值:若它的右子树不空,则右子树上所有结点的值均大于它 ...

  8. PTA 7-2 二叉搜索树的结构(30 分)

    7-2 二叉搜索树的结构(30 分) 二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值:若它的右子树不空,则右子树上所有结点的值均大 ...

  9. 二叉搜索树的结构(30 分) PTA 模拟+字符串处理 二叉搜索树的节点插入和非递归遍历

    二叉搜索树的结构(30 分) PTA 模拟+字符串处理 二叉搜索树的节点插入和非递归遍历   二叉搜索树的结构(30 分) 二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则 ...

随机推荐

  1. iis支持asp.net4.0的注册命令使用方法及部署网站注意事项

    如果没有按照正常的先装iis后装.net的顺序,可以使用以下命令重新注册一下,这样iis就可以支持asp.net 4.0了   32位的Windows: 1. 运行->cmd,打开窗口时请以管理 ...

  2. logback.xml文件配置(按时间、文件大小和log名称生成日志)

    之前项目中日志多用的log4j2,偶然看到在importNew看到了logback,自己查了下,发现Logback和log4j是非常相似的,其作者也是同一个人,并且logback相比于log4j性能更 ...

  3. 判断弹出框存在(alert_is_ present)

    系统弹窗这个是很常见的场景,有时候它不弹出来去操作的话,会抛异常.那么又不知道它啥时候会出来,那么久需要去判断弹窗是否弹出了 判断 alert 源码分析 class alert_is_present( ...

  4. Java日记

    总结关于Java web一些知识 VisualVM性能分析    ——  更好的理解JVM中的参数 JVM初始    ——    理解JVM 自己的Java开发规范  ——  个人Java开发是遵循的 ...

  5. Mybatis多参数

    转载自:一杯甜酒 http://blog.csdn.net/u012562943/article/details/52316071 据我目前接触到的传多个参数的方案有三种.第一种方案 DAO层的函数方 ...

  6. bzoj 3064: Tyvj 1518 CPU监控

    Description 1.区间加 \(z\) 2.区间覆盖为 \(z\) 3.查询区间最大值 4.查询区间历史最大值 Solution 线段树维护历史最值,思想大致是维护标记出现过的最大值 考虑这种 ...

  7. 深入理解JavaScript系列(50):Function模式(下篇)

    介绍 本篇我们介绍的一些模式称为初始化模式和性能模式,主要是用在初始化以及提高性能方面,一些模式之前已经提到过,这里只是做一下总结. 立即执行的函数 在本系列第4篇的<立即调用的函数表达式> ...

  8. .Net程序员玩转Android系列之二~Android Framework概要(1)

    从windows操作系统说起 人们总是喜欢从将陌生的事物和自己所了解的东西关联起来,以加深对未知事物的了解,这一讲我们从windows操作系统说起,逐步引领带大家走入android的世界.写任何程序都 ...

  9. iframe适应屏幕大小,隐藏滚动条,移动端

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat=&qu ...

  10. AngularJS 指令 实现文本水平滚动效果

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...