第五章——数和二叉树2

数和二叉树(二)

二叉树的存储结构及实现

顺序存储结构
二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且结点的存储位置(下标)应能体现结点之间的逻辑关系——父子关系。
利用数组下标来反映结点之间的逻辑关系:
完全二叉树和满二叉树中结点的序号可以唯一地反映出结点之间的逻辑关系 。


二叉链表

基本思想:令二叉树的每个结点对应一个链表结点,链表结点除了存放与二叉树结点有关的数据信息外,还要设置指示左右孩子的指针。
在这里插入图片描述

template <class T>
struct BiNode
{
    T data;
    BiNode<T> *lchild, *rchild;
};

(具有n个结点的二叉链表中,有n+1个空指针。)

二叉链表存储结构的类声明:

template <class T>
class BiTree
{    
  public:
       BiTree(); 
        ~BiTree( );            
        void PreOrder(){PreOrder(root);} 
        void InOrder() {InOrder(root);} 
        void PostOrder() {PostOrder(root);} 
        void LevelOrder(){LeverOrder(root)};
  private:
        BiNode<T> *root; 
        BiNode<T> * Creat( ); 
        void Release(BiNode<T> *root);
        void PreOrder(BiNode<T> *root); 
        void InOrder(BiNode<T> *root); 
        void PostOrder(BiNode<T> *root); 
        void LevelOrder(BiNode<T> *root);
 };

前序遍历——递归算法

template   <class T>
void   BiTree::PreOrder(BiNode<T> *root) 
{
        if (root ==NULL)  return;     
        else {
            cout<<root->data;         
            PreOrder(           );    
            PreOrder(           );    
        }
 }

前序遍历——非递归算法
二叉树前序遍历的非递归算法的关键:
在前序遍历过某结点的整个左子树后,如何找到该结点的右子树的根指针。
解决办法:在访问完该结点后,将该结点的指针保存在栈中,以便以后能通过它找到该结点的右子树。
栈是实现递归的最常用的结构
前序遍历——非递归算法(伪代码)

1.栈s初始化(空栈);
2.循环直到root为空且栈s为空
 2.1 当root不空时循环
  2.1.1 输出root->data;
 2.1.2 将指针root的值保存到栈中;
 2.1.3 继续遍历root的左子树(root=root->lchild)
 2.2 如果栈s不空,则
  2.2.1 将栈顶元素弹出至root(root=s.pop());
  2.2.2 准备遍历root的右子树(root=root->rchild);

template <class T>
void BiTree::PreOrder(BiNode<T> *root) {
  SeqStack<BiNode<T> *>  s;
     while (root!=NULL | | !s.empty()) {
         while (root!= NULL)  {
             cout<<root->data;
             s.push(root);
             root=root->lchild;  
         }
         if (!s.empty()) { 
             root=s.pop();
             root=root->rchild;  
         }
     }
}

二叉树的建立
遍历是二叉树各种操作的基础,可以利用遍历的思想完成二叉树的各种操作,例如建立一棵二叉树。
设二叉树中的结点均为一个字符。假设扩展二叉树的前序遍历序列由键盘输入,root为指向根结点的指针,二叉链表的建立过程是:
1,按扩展前序遍历序列输入结点的值
2,如果输入结点值为“#”,则建立一棵空的子树
3,否则,根结点申请空间,将输入值写入数据域中,
4,以相同方法的创建根结点的左子树
5,以相同的方法创建根结点的右子树递归方法

中序遍历——递归算法

template <class T>
void BiTree::InOrder (BiNode<T> *root)
{
         if (root==NULL) return;     
         else {
               InOrder(root->lchild); 
               cout<<root->data; 
               InOrder(root->rchild);
         }
}

中序遍历——非递归算法(伪代码)
1.栈s初始化(空栈);
2.循环直到root为空且栈s为空
 2.1 当root不空时循环
2.1.1 将指针root的值保存到栈中;
 2.1.2 继续遍历root的左子树(root=root->lchild)
 2.2 如果栈s不空,则
  2.2.1 将栈顶元素弹出至root(root=s.pop());
   2.2.2 输出root->data;
  2.2.3 准备遍历root的右子树(root=root->rchild);

template <class T>
void BiTree::InOrderwithoutD (BiNode<T> *root)
  {
      stack< BiNode<T> * > aStack;
            while(!aStack.empty()||root) {
while(root){
  aStack.push(root);
  root=root->lchild;  
 }
     if(!aStack.empty()){
        root=aStack.top();    
        aStack.pop(); 
                 cout<<root->data;
                 root=root->rchild; 
    }
  }
} 

后序遍历——递归算法

template <class T>
void BiTree::PostOrder(BiNode<T> *root)
{ 
    if (root==NULL) return; 
    else {
         PostOrder(root->lchild); 
         PostOrder(root->rchild); 
         cout<<root->data;          
    }
}

非递归后序遍历二叉树
算法分析
①定义一个栈;从根节点出发开始遍历,p=root,如果,root==NULL, 不进行遍历;无条件进行下面的工作:如果指针不空,指针打上left标记,并将指针进栈,执行②;否则,执行③
②p=p->lchild,重复①
③栈顶元素出栈P
④查看P的标志,如果标志为right,进行下面的工作,否则,执行⑤
1)访问当前节点P
2)如果栈空 ,算法结束;
3)否则,栈顶元素出栈,转④
⑤修改P的标志,让P重新入栈,p=P->rchild,执行2
非递归后序遍历二叉树

栈中的元素类型定义StackElement
  enum Tags{Left,Right}; //特征标识定义
 template <class T>
 class StackElement  //栈元素的定义
 {
 public:
 BiTreeNode<T>* pointer;     //指向二叉树结点的指针
 Tags tag; //特征标识申明
 }; 

层序遍历
1.队列Q初始化;
2. 如果二叉树非空,将根指针入队;
3. 循环直到队列Q为空
3.1 q=队列Q的队头元素出队;
3.2 访问结点q的数据域;
3.3 若结点q存在左孩子,则将左孩子指针入队;
3.4 若结点q存在右孩子,则将右孩子指针入队;

#include <queue>
using namespace std;
template<class T>
void BiTree<T>::LevelOrder(BinaryTreeNode<T>* root){
 queue<BiTreeNode<T>*> aQueue;
 if(root)
  aQueue.push(root);
 while(!aQueue.empty())
{
  root=aQueue.front(); //取队列首结点
   aQueue.pop();
                     cout<<pointer->data;//访问当前结点
  if(root->lchild) //左子树进队列
   aQueue.push(root->lchild);
  if(root->rchild) //右子树进队列
   aQueue.push(root->rchild);  
 }//end while
}

二叉树 的析构

template<class T>
void BiTree<T>::Release(BiNode<T>* root){
  if (root != NULL){                  
      Release(root->lchild);   //释放左子树
      Release(root->rchild);   //释放右子树
      delete root;
  }  
}
template<class T>
BiTree<T>::~BiTree(void)
{
 Release(root);
}

树中节点的数目

template<class T>
int BiTree<T>::count(BiNode<T>* root){
 int number=0;
if (root==NULL)
  number=0;
 else
  number=count(root->lchild)+count(root->rchild)+1;
 return number;
}

计算树的高度
高度的定义
max(左子树高度,右子树高度)+1
算法分析
从根节点出发开始计算,
如果root==NULL, 高度为0;
否则,分别计算左子树的高度;右子树的高度;返回max(左子树高度,右子树高度)+1
递归的定义

template<typename T> 
 int BiTree<T>::cal_height(BiTreeNode<T> * root){
 int lheight=0,rheight=0;
 if (root==0)    return 0; 

输出中缀表达式。并加上相应的括号
(a+(b*(c-d)))-(e/f)
基本思想
中序遍历。
中序遍历左子树前,输出左括号
中序遍历右子树后,输出右括号
如果遍历叶子结点的左右子树,不输出括号
如果遍历根节点的左右子树,不输出括号(否则,会得到形如(a+b)的表达式)

void BiTree<T>::In_Expression(BiNode<T>* root){
 if(root)
 {
      if(root!=this->root&&root->lchild!=0&&root->rchild!=0)
              cout<<"(";
    In_Expression(root->lchild);
    cout<<root->data;
       In_Expression(root->rchild);
     if(root!=this->root&&root->lchild!=0&&root->rchild!=0)
   cout<<")";
 }
 
}

计算二叉树的宽度
所谓宽度是指在二叉树的各层上,具有结点数最多的那一层上的结点总数

struct q_element{ BiNode * root;  int level;};
int BiTree::Width(){
 queue< struct q_element > q;
 int num[100]={0,1};
 q_element s,child;
 BiNode *root;
 root=this->root;
 if(root==NULL)
  return 0;
 s.root=root; s.level=1; q.push(s); 
 while(!q.empty()) {
  s=q.front();
  if(s.root->lchild){
   num[s.level+1]++;
   child.root=s.root->lchild;
   child.level=s.level+1;
   q.push(child);
  }
if(s.root->rchild) {
   num[s.level+1]++;
   child.root=s.root->rchild;
   child.level=s.level+1;
   q.push(child);
  }
  q.pop();
 }
 int max=0,i=1;
 while(num[i]>0){
  if(max<num[i])
   max=num[i];
  i++;
 }
 
 return max;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泡泡>3<

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值