二叉树相关知识《1》

二叉树的逻辑结构

1>二叉树只有两个分支,左子树和右子树


2>斜树


3>满二叉树:每一个分支节点都有一个左子树和右子树,而且所有叶子都在同一层上,叶子只能出现在最下面一层;只有度为0和度为2的结点


4> 完全二叉树:满二叉树去掉一些连续的结点就变成了完全二叉树,就是总最后一层开始删除,而且是从右到左去删除的才能称之为完全二叉树
 

二叉树的基本性质:

1>第i层上最多只有2的i-1次方的结点
2>深度为k的二叉树中,最多有2的k次方-1个结点,最少有k个结点
3>树中的结点数=叶子结点数(叶子的个数)+度为2的结点的个数【几个式子推出来的】
4>完全二叉树的深度为
5> 结点i的
双亲结点为i/2
左孩子结点为2i  右孩子结点为2i+1

二叉树的存储结构:

结构体

struct biNode
{

char data;
biNode *lchild,*rchild;
}

二叉树的遍历

1>前序 【先访问左子树,然后再是右子树】很明显的递归味
void Bitree::preorder(Binode *bt)
{

   if(bt==NULL)
   return ;
  else
  {
   visit(bt->data);
  preorder(bt->lchild);
  preorder(bt->rchild);
  }
}


2>中序【根节点在中间被遍历】使用 2 1 3 的方法去套每一个字母,前后都可以使用这种方法

struct Bitree::inorder(binode *bt)
{
    if(bt==NULL)
    return ;
  else

  {

   inorder(bt->lchild);
  visit(bt->data);
  inorder(bt->rchild);
   }

}

3>后序
struct Bitree::postorder(binode *bt)
{
    if(bt==NULL)
    return ;
 else
 
   {
    visit(bt->data);
    postorder(bt->lchild);
    postorder(bt->rchild);
   }

}


4>层序

#include<queue>

struct Bitree::leverorder()
{
  if(root==NULL)//二叉树为空
   return ;
else
 
 {
       queue.enQueue(root);
      while(!queue.isempty())
    {
      q=queue.deQueue();
      visit(q->data);
     if(q->lchild)!=NULL)
     queue.enqueue(q->lchild);
     if(q->rchild!=NULL)
     queue.enqueue(q->rchild);
    }

  }

}

二叉树的创建:

前序创建:

BiTree::BiTree()
  {
    root = creat(root);//调函数构建二叉树
  }
Bitree* BItree::creat(binode *bt)
{
    
    input(ch);
    if(ch=='#')
    {
        bt=NULL;
    }
    else
    {
        bt=new binode;
        bt->data=ch;
        bt->lchild=creat(bt->lchild);
        bt->rchild=creat(bt->rchild);
    }
    return bt;
}

第二种:

BiTree::BiTree()
{
Creat(root);
}

void BItree::creat(binode * &bt)
{
    
    input(ch);
    if(ch=='#')
    {
        bt=NULL;
    }
    else
    {
        bt=new BiNode;
        bt->data=ch;
        Creat(bt->lchild);
        Creat(bt->rchild);
    }
    return ;
}

这两种方法最大的区别就是括号中传入的指针加了一个应用符号&

原因是:

 在C++中,使用引用符号&是为了能够修改指针变量本身,而不仅仅是修改指针所指向的内容。这是因为在C++中,函数参数的传递默认是按值传递的,即使对于指针类型,传递给函数的也是指针的值(即地址),而不是指针本身。如果在函数内部修改了指针的值(即让它指向另一个地址),这种修改不会影响到函数外部的原始指针。为了让函数能够修改外部的指针变量,需要传递指针的引用。

二叉树的删除函数

void BiTree::release(BiNode *bt)
{

        if(bt->lchild!=NULL)
       {
           release(bt->lchild);
       }


       if(bt->rchild!=NULL)
        {
            release(bt->rchild);
        }
//        if(bt->rchild==NULL&&bt->lchild==NULL)
//        {
            cout<<"delete  "<<bt->data<<endl;
            delete bt;
       // }



}

那三条//函数,如果把//去掉的话(也就是不注释),那么最后两个数据删不掉

可以用一个例子来解释最后一句话:

二叉树的扩展前序序列

AB##C##

传入A之后,经过两个判断语句后进入了删除左指针和右指针的递归函数,进行完这两个递归函数后B,C位置的指针就变成了野指针,这个时候再来进行if(bt->rchild==NULL&&bt->lchild==NULL)判断的话,就会出错【root->lchild为野指针,他的值不是空]

总共的二叉树函数

/**字符串建树 并实现遍历(待填充代码)*/
#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
struct BiNode
{
    char data;//数据域
    BiNode  *lchild, *rchild;//左右儿子指针
};


class BiTree {
private:
  BiNode *root;              //指向根结点的头指针

public:
  BiTree()
  {
    root = creat(root);//调函数构建二叉树
  }
  ~BiTree()
  {
  //	release(root);
  }
  BiNode * getRoot(){return root;}
  BiNode *creat(BiNode *bt); //构造函数调用
  void release(BiNode *bt);  //析构函数调用,释放树的存储空间
  void preOrder(BiNode *bt); //前序遍历函数调用
  void inOrder(BiNode *bt);  //中序遍历函数调用
  void postOrder(BiNode *bt);//后序遍历函数调用
  void leverOrder(BiNode *bt);//后序遍历函数调用
};

/**前序构建二叉树*/
BiNode* BiTree::creat(BiNode *bt)
{
    char ch;
   cin>>ch;
    if(ch=='#')
    {
        bt=NULL;
    }
    else
    {
        bt=new BiNode;
        bt->data=ch;
       bt->lchild=creat(bt->lchild);
       bt->rchild=creat(bt->rchild);
    }
    return bt;

}

void BiTree::release(BiNode *bt)
{

        if(bt->lchild!=NULL)
       {
           release(bt->lchild);
       }


       if(bt->rchild!=NULL)
        {
            release(bt->rchild);
        }

            cout<<"delete  "<<bt->data<<endl;
            delete bt;




}




/**前序遍历*/
void visit(char ch)
{
    cout<<ch;
}

void BiTree::preOrder(BiNode * bt)
{
    if(bt==NULL)
    {
        return ;
    }
    else
    {
        visit(bt->data);
        preOrder(bt->lchild);
        preOrder(bt->rchild);

    }
}

void BiTree::inOrder(BiNode *bt)
{
    if(bt==NULL)
    {
        return ;
    }
    else
    {
        inOrder(bt->lchild);
         visit(bt->data);
        inOrder(bt->rchild);
    }
}

void BiTree::postOrder(BiNode *bt)
{
    if(bt==NULL)
    {
        return ;
    }
    else
    {
        postOrder(bt->lchild);
        postOrder(bt->rchild);
        visit(bt->data);
    }
}


void BiTree::leverOrder(BiNode *root)
{
  if(root==NULL)//二叉树为空
   return ;
  else
     {
         /*那么我们来思考一下,这里为什么不能是
          queue<BiNode> h;//创建一个队列 类型
         h.push(*root);这个样子写的话,漏洞百出

         */
         queue<BiNode*> h;//创建一个队列 类型
         h.push(root);//将根指针放进去
         while(!h.empty())
          {

            BiNode* q=h.front();
            h.pop();
            visit(q->data);
            if(q->lchild!=NULL)
            h.push(q->lchild);
            if(q->rchild!=NULL)
            h.push(q->rchild);
           }

      }

}




int main()
{

    BiTree tree;

//    cout << "\n前序遍历二叉树"<<endl;
//    tree.preOrder(tree.getRoot());
//
//
//    cout << "\n中序遍历二叉树"<<endl;
//    tree.inOrder(tree.getRoot());
//    cout<<endl;
//
//
//    cout << "\n后序遍历二叉树"<<endl;
//    tree.postOrder(tree.getRoot());
//
//
//     cout << "\n层序遍历二叉树"<<endl;
    tree.leverOrder(tree.getRoot());

//    cout<<"\n删除的结果为:"<<endl;
    return 0;
}

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值