二叉树的实现

二叉树的存储结构及实现

顺序存储结构

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

  • 前序遍历
void Preorder(int root, char data[]){
	if(data[root]!='\0'){
		cout<<data[root] ;			
		Preorder(2*root,data);
		Preorder(2*root+1,data);
	}
	return;
}

  • 中序遍历
void InOrder(int root, char data[]){
	if(data[root]!='\0'){
		InOrder(2*root,data);
		cout<<data[root] ;			
		 InOrder(2*root+1,data);	
	}
	return;
}

  • 后序遍历
void PostOrder(int root, char data[]){
	if(data[root]!='\0'){
		 PostOrder(2*root,data);
		 PostOrder(2*root+1,data);
		cout<<data[root] ;			
	}
	return;
}

构建:
void create(char preorder[],char inorder[],int start_p, int end_p,int start_i,int end_i, char data[],int root){
	if(start_p>end_p)
		return ;
	else{
		int k;
		for(int i=start_i;i<=end_i;i++){
			if(inorder[i]==preorder[start_p]){
				k=i;
				break;
			}
		}
		data[root]=preorder[start_p];
		create(preorder,inorder,start_p+1,start_p+k-start_i,start_i,k-1,data, 2*root);
		create(preorder,inorder,start_p+k-start_i+1,end_p,k+1,end_i,data,2*root+1);
	}
	return ;
}

二叉链表

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

  • 节点信息
template <class T>
struct BiNode
{
    T data;
    BiNode<T> *lchild, *rchild;
};

  • 类声明
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(root->lchild);    
            PreOrder(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;  
         }
     }
}

  • 中序遍历——递归算法
template <class T>
void BiTree::InOrder (BiNode<T> *root)
{
         if (root==NULL) return;     
         else {
               InOrder(root->lchild); 
               cout<<root->data; 
               InOrder(root->rchild);
         }
}

template<class T>
BiTree<T>::BiTree( )
{
	Creat(root);
}
template <class T>
void BiTree<T>::Creat(BiNode<T> * &root  )
{
	T ch;
	cout<<"请输入创建一棵二叉树的结点数据"<<endl;
	cin>>ch;
         if (ch=="#") root = NULL;
         else{ 
	     root = new BiNode<T>; 
                  root->data=ch;
                  Creat(root->lchild );
                  Creat(root->rchild); 
    } 
}

  • 非递归中序遍历二叉树
template <class T>
void BiTree::InOrderwithoutD (BiNode<T> *root)
{
    stack< BiNode<T> * > aStack;
    while(root)
    {
        aStack.push(root);
        root=root->lchild;
    }
    if(!aStack.empty())
    {
        root=aStack.top();
        aStack.pop();
        cout<<root->data;
        root=root->rchild;
    }
}

  • 非递归后序遍历二叉树
enum Tags {Left,Right};	//特征标识定义
template <class T>
class StackElement		//栈元素的定义
{
public:
    BiTreeNode<T>* pointer;     //指向二叉树结点的指针
    Tags tag; //特征标识申明
};
template<class T>
void BiTree<T>::PostOrderWithoutRecusion(BiTreeNode<T>* root)
{
    StackElement<T> element;
    stack<StackElement<T > > aStack;//栈申明
    BiTreeNode<T>* pointer;
    if(root==NULL)
        return;//空树即返回
    else
        pointer=root;
    while(true)
    {
        while(pointer!=NULL) //进入左子树
        {
            element.pointer=pointer;
            element.tag=Left; //沿左子树方向向下周游
            aStack.push(element);
            pointer=pointer->lchild;
        }
        element=aStack.pop();
        pointer=element.pointer;
        while(element.tag==Right)
        {
            cout<<pointer->data;
            if(aStack.empty())
                return;
            else
            {
                element=aStack.pop();
                pointer=element.pointer;
            }//end else
        } //endwhile
        element.tag=Right;
        aStack.push(element);
        pointer=pointer->rchild();
    }//end while
}

  • 二叉树 层次遍历
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>
struct Node
{
	T data;
	Node<T> * lchild, *rchild,*parent;
};

template <class T>
BiNode<T> * BiTree<T>::Creat(BiNode<T> * &root,BiNode<T> *parent)
{
    T ch;
    cout<<"请输入创建一棵二叉树的结点数据"<<endl;
    cin>>ch;
    if (ch=="#")
        root = NULL;
    else
    {
        root = new BiNode<T>;       //生成一个结点
        root->data=ch;
        root->parent=parent;
        Creat(root->lchild,root );    //递归建立左子树
        Creat(root->rchild,root);    //递归建立右子树
    }
    return root;
}

template<class T>
BiTree<T>::BiTree( int i)
{
    number=0;
    Creat(root,NULL);
}

森林转换为二叉树
  1. 将森林中的每棵树转换成二叉树;
  2. 从第二棵二叉树开始,
  3. 依次把后一棵二叉树的根结点作为前一棵二叉树根结点的右孩子,
  4. 当所有二叉树连起来后,此时所得到的二叉树就是由森林转换得到的二叉树。
二叉树转换为树或森林
  1. 加线——若某结点x是其双亲y的左孩子,则把结点x的右孩子、右孩子的右孩子、……,都与结点y用线连起来;
  2. 去线——删去原二叉树中所有的双亲结点与右孩子结点的连线;
  3. 层次调整——整理由⑴、⑵两步所得到的树或森林,使之层次分明。
森林的遍历
  • 前序(根)遍历:前序遍历森林即为前序遍历森林中的每一棵树。
  • 后序(根)遍历:后序遍历森林即为后序遍历森林中的每一棵树。
哈夫曼树

给定一组具有确定权值的叶子结点,带权路径长度最小的二叉树。

哈夫曼树的特点:

权值越大的叶子结点越靠近根结点,而权值越小的叶子结点越远离根结点。
只有度为0(叶子结点)和度为2(分支结点)的结点,不存在度为1的结点.
哈夫曼算法基本思想:

  1. 初始化:由给定的n个权值 w 1 , w 2 , … , w n {w_{1},w_{2},…,w_{n}} w1w2wn构造n棵只有一个根结点的二叉树,从而得到一个二叉树集合 F = T 1 , T 2 , … , T n ; F={T_{1},T_{2},…,T_{n}}; FT1T2Tn
  2. 选取与合并:在F中选取根结点的权值最小的两棵二叉树分别作为左、右子树构造一棵新的二叉树,这棵新二叉树的根结点的权值为其左、右子树根结点的权值之和;
  3. 删除与加入:在F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到F中;
  4. 重复⑵、⑶两步,当集合F中只剩下一棵二叉树时,这棵二叉树便是哈夫曼树。

哈夫曼算法的存储结构

设置一个数组 h u f f T r e e [ 2 n − 1 ] huffTree[2n-1] huffTree[2n1]保存哈夫曼树中各点的信息,数组元素的结点结构 :
二叉树的实现_第1张图片

struct element
{     int weight;
      int lchild, rchild, parent;
};

void HuffmanTree(element huffTree[ ], int w[ ], int n ) {
    for (i=0; i<2*n-1; i++) {
       huffTree [i].parent= -1;
       huffTree [i].lchild= -1;
       huffTree [i].rchild= -1;   
    }
    for (i=0; i<n; i++) 
       huffTree [i].weight=w[i];
    for (k=n; k<2*n-1; k++) {
        Select(huffTree, &i1, &i2); 
        huffTree[k].weight=huffTree[i1].weight+huffTree[i2].weight;
        huffTree[i1].parent=k;     
        huffTree[i2].parent=k; 
        huffTree[k].lchild=i1;    
        huffTree[k].rchild=i2;
    }
}

哈夫曼树应用——哈夫曼编码

前缀编码:一组编码中任一编码都不是其它任何一个编码的前缀
从叶子结点到根, 逆向求每个叶子结点对应的哈夫曼编码,根据 h u f f m a n huffman huffman树中叶子节点的个数,构造一个字符串数组,每个数组分量是一个字符串,用于存放该节点对应的 h u f f m a n huffman huffman编码。

你可能感兴趣的:(数据结构笔记)