山东大学 数据结构 实验6 堆和搜索树

实验六  堆和搜索树

一、 要求完成时间

实验开始后的第七周之前完成

二、 实验目的

掌握堆和搜索树的基本概念,插入、删除方法。

三、 实验内容

1、 输入一系列不为零的正整数(最多不超过20个),遇到0代表输入结束(不包含0)。

2、 根据上面输入的数据序列,用初始化方法创建最大堆(不要用节点依次插入的办法创建最大堆),然后输出最大堆的层次序列。

3、 输出用堆排序后的排序结果。

4、 根据上面输入的数据,创建二叉搜索树(关键字不允许重复,如遇重复,则不重复插入该关键字),输出二叉搜索树的前序序列、中序序列(分行输出)。

四、 测试用例及答案

测试如下所有用例及答案,且确保运行后出现完全一样的输出,

(操作系统提示“请按任意键继续….”等,可以不一样。)

 


分析:

1.堆排序:借助最大堆的定义,返回的肯定是堆内最大的元素,将堆内的元素依次弹出,直到堆为空。这样就实现了排序。

 

2.BSTree继承自前面实验的BinaryTree以减少类方法的设计。只需根据二叉搜索树的定义,在插入、删除时,根据元素的大小遍历左子树或右子树。

 

以下是代码,有点略多,仅供参考,希望你写出更好的方法!


代码:

#include<iostream>
#include<string>
using namespace std;
class OutOfBounds {
public:
    OutOfBounds(){
        cout<<"Out of bounds!"<<endl;
    }
};
 
class NoMen{
public:
    NoMen(){
        cout<<"NoMen error!"<<endl;
    }
};

//处理数BadInput的报错
class BadInput{    
    public:    
        BadInput(){    
        	cout<<"BadInput!"<<endl;    
        }    
}; 
class NoElement{
	public:
		NoElement(){
			cout<<"NoElement!"<<endl;
		}
};
//类最大堆 
template<class T>
class MaxHeap{
	public:
		MaxHeap(int MaxHeapSize = 10);
		~MaxHeap(){delete [] heap;}
		int Size() const{return CurrentSize;}
		T Max(){if(CurrentSize == 0) throw OutOfBounds();
			return heap[1];}
		MaxHeap<T>& Insert(const T& x);
		MaxHeap<T>& DeleteMax(T& x);
		void Initialize(T a[],int size,int ArraySize);
		void Output(); 
	private:
		int CurrentSize,MaxSize;
		T *heap;//元素数组 
};
template<class T>
MaxHeap<T>::MaxHeap(int MaxHeapSize){
	MaxSize = MaxHeapSize;
	heap = new T[MaxSize+1];
	CurrentSize = 0;
} 
template<class T>
MaxHeap<T>& MaxHeap<T>::Insert(const T& x){
	//把x插入到最大堆中
	if(CurrentSize == MaxSize)
		throw NoMen();
		
	//为x寻找插入位置
	//i从新的叶节点开始,并沿着树上升
	int i = ++CurrentSize;
	while(i != 1 && x > heap[i/2]){
		//不能够把x放入heap[i]
		heap[i] = heap[i/2];//将元素下移
		i /= 2;//移向父节点 
	} 
	
	heap[i] = x;
	return *this; 
}
template<class T>
MaxHeap<T>& MaxHeap<T>::DeleteMax(T& x){
	//将最大元素放入x,并从堆中删除最大元素
	
	//检查堆是否为空
	if(CurrentSize == 0)
		throw OutOfBounds();
	
	x = heap[1];
	
	//重构堆
	T y = heap[CurrentSize--];
	//从根节点开始,为y寻找合适的位置
	int i = 1;//堆的当前节点
	int ci = 2;//i的孩子
	while(ci <= CurrentSize){
		//heap[ci]应是i的比较大的孩子
		if(ci < CurrentSize && heap[ci] < heap[ci+1])
			ci++;
			
		if(y >= heap[ci])
			break;
		
		heap[i] = heap[ci];
		i = ci;
		ci *= 2; 
	} 
	heap[i] = y;
	return *this;
}
template<class T>
void MaxHeap<T>::Initialize(T a[],int size,int ArraySize){
	//把最大堆初始化为数组a
	delete [] heap;
	heap = a;
	CurrentSize = size;
	MaxSize = ArraySize;
	
	//产生一个最大堆
	for(int i = CurrentSize/2;i >= 1;i--){
		T y = heap[i];//子树的根
		//寻找放置y的位置
		int c = 2*i;//c的父节点是y的目标位置
		while(c <= CurrentSize){
			if(c < CurrentSize && heap[c] < heap[c+1])
				c++;
				
			if(y >= heap[c])
				break;
			
			heap[c/2] = heap[c];
			c *= 2;
		} 
		heap[c/2] = y;
	} 
}
template<class T>
void MaxHeap<T>::Output(){
	for(int i = 1;i <= MaxSize;i++){
		cout<<heap[i];
		if(i != MaxSize)
			cout<<",";
	}
} 
//类BinaryTreeNode
template<class T>
class BinaryTreeNode {
                 public:
                            BinaryTreeNode() {LeftChild=RightChild=NULL;}
                            BinaryTreeNode(const T&e)
                              {
                                data=e;
                                LeftChild=RightChild=NULL;
                              }
                            BinaryTreeNode(const T&e, BinaryTreeNode *l,
                                                BinaryTreeNode *r)
                              {
                                 data=e;
                                 LeftChild=l;
                                 RightChild=r;
                              }

                            BinaryTreeNode<T> *LeftChild;    //左子树
                            BinaryTreeNode<T> *RightChild;   //右子树
                            T data;
                            };

//类BinaryTree
template<class T>
class BinaryTree{
             public:
                      BinaryTree(){root=NULL;}

                      ~BinaryTree(){Delete();}

                      void Delete(){PostOrder(Free, root); root=0;}

                      static void Free(BinaryTreeNode<T>* t){delete t;}

                      int IsEmpty()const
                        {return ((root) ? 0 : 1);}

                      int Root(T& x)const;

                      void MakeTree(const T& element, BinaryTree<T>& left,
                                         BinaryTree<T>& right);

                      void BreakTree(T& element, BinaryTree<T>& left,
                                          BinaryTree<T>& right);

                      void PreOrder(void(*Visit)(BinaryTreeNode<T> *u))
                            {PreOrder(Visit, root);}

                      void InOrder(void(*Visit)(BinaryTreeNode<T> *u))
                            {InOrder(Visit, root);}

                      void PostOrder(void(*Visit)(BinaryTreeNode<T> *u))
                            {PostOrder(Visit, root);}

                      BinaryTreeNode<T>* root;  //根节点指针 

                    //遍历方法
                      void PreOrder(void(*Visit)
                          (BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);

                      void InOrder(void(*Visit)
                          (BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);

                      void PostOrder(void(*Visit)
                          (BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);
					//为了输出, 
					  void PreOrder(void(*Visit)(BinaryTreeNode<T> *u,int i),BinaryTreeNode<T> *t,int i);
					  void InOrder(void(*Visit)(BinaryTreeNode<T> *u,int i),BinaryTreeNode<T> *t,int i);
					  void PostOrder(void(*Visit)(BinaryTreeNode<T> *u,int i),BinaryTreeNode<T> *t,int i);	
						
                      static void Output(BinaryTreeNode<T> *t)
                             {
                              cout << t->data << " ";
                             }
                      static void Output2(BinaryTreeNode<T> *t,int i)
					  		 {
							  if(i != 0)cout<<",";
						      cout<<t->data;
					  		 }

                      void PreOutput()
                        {
                          static int i = 0;PreOrder(Output2,root,i);
                          cout << endl;
                        }

                      void InOutput()
                         {
                          static int i = 0;InOrder(Output2,root,i);
                          cout << endl;
                         }

                      void PostOutput()
                         {
                          static int i = 0;PostOrder(Output2,root,i);
                          cout << endl;
                         }
                     };

//类BSTree
template<class E, class K>
class BSTree : public BinaryTree<E>{
         public:
                    int Search(const K& k, E& e)const;
                    BSTree<E,K>& Insert(const E& e);
                    BSTree<E,K>& Delete(const K& k, E& e);
                    //在e中存储树的最大元素
                    void MaxNode(E& e)const;
         };


/*---------------------BinaryTree Methods()-------------------------*/
template<class T>
int BinaryTree<T>::Root(T& x) const
  { //取根节点的data域,放入x 
    //如果没有根节点,则返回false 
    if(root)
      {
        x=root->data;
        return 1;
      }
    else return 0;  //没有根节点 
  }

template<class T>
void BinaryTree<T>::MakeTree(const T& element,
                      BinaryTree<T>& left, BinaryTree<T>& right)
  {//将left, right,和 element 合并成一棵新树 
    //left, right和 this必须是不同的树 
    //创建新树 

    root=new BinaryTreeNode<T>(element, left.root, right.root);

    //阻止访问left和right 
    left.root=right.root=0;
  }

template<class T>
void BinaryTree<T>::BreakTree(T& element,
                        BinaryTree<T>& left, BinaryTree<T>& right)
  {//left, right和 this必须是不同的树 
    //检查树是否为空 

    if(!root)  //空树
    	throw BadInput();

    //分解树 
    element=root->data;
    left.root=root->LeftChild;
    right.root=root->RightChild;

    delete root;
    root=0;
  }

template<class T>
void BinaryTree<T>::PreOrder(void(*Visit)
                        (BinaryTreeNode<T>* u), BinaryTreeNode<T>* t)
  {//前序遍历

     if(t)
      {
        Visit(t);
        PreOrder(Visit, t->LeftChild);
        PreOrder(Visit, t->RightChild);
      }
  }

template<class T>
void BinaryTree<T>::InOrder(void(*Visit)(BinaryTreeNode<T>* u),
                                     BinaryTreeNode<T>* t)
  {//中序遍历 

      if(t)
         {
          InOrder(Visit, t->LeftChild);
          Visit(t);
          InOrder(Visit, t->RightChild);
         }
  }

template<class T>
void BinaryTree<T>::PostOrder(void(*Visit)(BinaryTreeNode<T>* u),
                                        BinaryTreeNode<T>* t)
  {//后序遍历 

     if(t)
      {
        PostOrder(Visit, t->LeftChild);
        PostOrder(Visit, t->RightChild);
        Visit(t);
      }
  }
  
//为了输出,
template<class T>
void BinaryTree<T>::PreOrder(void(*Visit)(BinaryTreeNode<T> *u,int i),BinaryTreeNode<T> *t,int i){
	if(t){
		Visit(t,i);
		PreOrder(Visit,t->LeftChild,++i);
		PreOrder(Visit,t->RightChild,++i);
	}
} 
template<class T>
void BinaryTree<T>::InOrder(void(*Visit)(BinaryTreeNode<T> *u,int i),BinaryTreeNode<T> *t,int i){
	if(t){
		InOrder(Visit,t->LeftChild,i);
		if(t->LeftChild)i++;
		Visit(t,i++);
		InOrder(Visit,t->RightChild,i);
	}
} 
template<class T>
void BinaryTree<T>::PostOrder(void(*Visit)(BinaryTreeNode<T> *u,int i),BinaryTreeNode<T> *t,int i){
	if(t){
		PostOrder(Visit,t->LeftChild,i);
		PostOrder(Visit,t->RightChild,i);
		Visit(t,i++);
	}
} 
/*----------------------End of BinaryTree Methods()------------------*/

/*------------------------BSTree Methods()---------------------------*/

template<class E, class K>
int BSTree<E,K>::Search(const K& k, E& e) const
 {//搜索与k匹配的元素 
    //指针p从树根开始进行查找 
    
    BinaryTreeNode<E> *p=this->root;

     while(p) //检查p->data 
      {
        if(k<p->data)
          p=p->LeftChild;
        else if(k>p->data)
          p=p->RightChild;
        else{ //找到元素 
              e=p->data;
              return 1;
             }
      }
     return 0;
  }

template<class E, class K>
BSTree<E,K>& BSTree<E,K>::Insert(const E& e)
 { //如果不出现重复,则插入e 

  BinaryTreeNode<E> *p=NULL;   //搜索指针 
  BinaryTreeNode<E> *pp=NULL;     //p的父节点指针 

  //寻找插入点 
  p=this->root;       //p is now the root

  while(p)
    {
     pp=p;
     //将p移向孩子节点 

     if(e<p->data)
      p=p->LeftChild;

     else if(e>p->data)
      p=p->RightChild;

     else
      return *this; //出现重复,不插入,直接返回 
     }

    //为e建立一个节点,并将该节点连接至to pp 
    BinaryTreeNode<E> *r=new BinaryTreeNode<E>(e);

     if(this->root)
      {//树非空 

        if(e<pp->data)
         pp->LeftChild=r;

        else if(e>pp->data)
         pp->RightChild=r;
      }

     else //插入到空树中 
        this->root=r;

    return *this;
  }

template<class E, class K>
BSTree<E,K>& BSTree<E,K>:: Delete(const K& k, E& e)
 {//删除关键值为k的元素,并将其放入e 
 
  //将p指向关键值为k的节点 
  BinaryTreeNode<E> *p=NULL;  //搜索指针 
  BinaryTreeNode<E> *pp=NULL;  //p的父节点指针 

  p=this->root;

  while(p && p->data != k)
    {//移动到p的孩子 

     pp=p;

      if(k < p->data)
        p=p->LeftChild;

      else
        p=p->RightChild;
    }

  if(!p)               //没有关键值为k的元素 
    throw NoElement();

  e=p->data;    //保存欲删除的元素 

  //对树进重构 
    if(p->LeftChild && p->RightChild) //处理p有两个孩子的情形 
      {//转换成有0或1个孩子的情形 
        //在p的左子树中寻找最大元素 

        BinaryTreeNode<E> *s=p->LeftChild; 
        BinaryTreeNode<E> *ps=p;  //s的父节点 

        while(s->RightChild)
         {//移动到较大的元素 
          ps=s;
          s=s->RightChild;
         }

        //将最大元素从s移动到p 
        p->data=s->data;
        p=s;
        pp=ps;
      }//end all if

    //p最多有一个孩子 
    //在c中保存孩子节点 
    BinaryTreeNode<E> *c;

    if(p->LeftChild)
     c=p->LeftChild;

    else
     c=p->RightChild;
    //删除p 

    if(p==this->root)
      this->root=c;

    else{
          //p是pp的左孩子还是pp的右孩子? 
             if(p==pp->LeftChild)
              pp->LeftChild=c;

             else
              pp->RightChild=c;
         }
    delete p;
    return *this;
 }

template<class E, class K>
void BSTree<E,K>::MaxNode(E &e)const
 {//function returns max. value of tree (rightmost value)

  BinaryTreeNode<E>* p=NULL;  //root node
  BinaryTreeNode<E>* pp=NULL; //parent of p

  p=this->root;

  while(p)
    {
     pp=p;
     p=p->RightChild;
    }
     //p points to NULL, pp points to node before NULL
 e=pp->data; //max. value stored
 }

int main(){
	//最大堆部分 
	BSTree<int,int> abst;
	
	int a [22];
	int length = 0;
	cout<<"Input"<<endl;
	for(int i = 0;i < 21;i++){
		cin>>a[i+1];
		if(a[i+1] != 0)
			abst.Insert(a[i+1]);
		if(a[i+1] == 0)break;
		length++;
	}
	cout<<"Output"<<endl;
	//初始化最大堆
	MaxHeap<int> oneMaxHeap;
	oneMaxHeap.Insert(0);
	oneMaxHeap.Initialize(a,length,length);
	oneMaxHeap.Output();
	cout<<endl;
	//堆排序
	int array[length];
	for(int i = 0;i < length;i++){
		oneMaxHeap.DeleteMax(array[length-1-i]);
	}
	for(int i = 0;i < length;i++){
		cout<<array[i];
		if(i != length-1)
			cout<<",";
	}
	cout<<endl;
	
	//二叉搜索树部分 
 	abst.PreOutput();
 	abst.InOutput();
 	cout<<"End"<<endl;
	return 0; 
} 

运行截图:


ps:本人开通了个人的微信公众号,希望大家能关注一下,

我会将资源、文章优先推送到公众号上。

推送自己的一些学习笔记,实验源代码等,

欢迎大家互相交流学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值