山东大学数据结构实验6-堆和搜索树(c++实现)(超详细注释)

山东大学数据结构实验6-堆和搜索树(c++实现)

内含方法:下沉操作,创建最大堆,堆排序,插入法创建搜索树,前序遍历,中序遍历

#include<iostream>
#include<vector>
int count1=0;
int count2=0;//用count2记录数组中有几个重复的值
bool flag=true;//使用flag判断数组中是否有重复的值
using namespace std;
typedef struct Bnode
{
    int data;
    struct Bnode *lchild,*rchild;//*lchild左孩子指针  *rchild右孩子指针
}Bnode,*Btree;
//下沉操作
void Sink(int k,int n,vector<int> &r)
{
    while(2*k<=n)//如果有左孩子,k的左孩子为2k,右孩子为2k+1
    {
        int j=2*k;//j指向左孩子
        if(j<n&&r[j-1]<r[j])//如果有右孩子,且右孩子比左孩子大
        j++;//j指向右孩子
        //由于是用数组存储,r[0]存储的才是第一个节点,所以第k个节点被存储在r[k-1]
        if(r[k-1]>=r[j-1])//如果k比大的孩子还要大,则说明已经满足最大堆的性质
        break;
        else//否则与较大的孩子交换
        {
            int t=r[k-1];
            r[k-1]=r[j-1];
            r[j-1]=t;
        }
        k=j;//k,指向交换后的新位置,继续向下比较,直到下沉到叶子
    }
}
//最大堆:每一个节点的值都大于等于左右孩子的值;最小堆:每一个节点的值都小于等于左右孩子的值
//创建最大堆
/*
1:按照完全二叉树的顺序构建一棵完全二叉树
2:从最后一个分枝节点n/2(节点是int型的,如果为小数,则直接舍掉小数点后的数,不会四舍五入)开始调整,依次将序号为n/2-1,n/2-2....1的节点执行下沉操作,调整为堆,即可构建最大堆。
*/
void CreatHeap(int n,vector<int> &r){
    for(int i=n/2;i>0;i--)//从最后一个分枝节点n/2开始下沉调整为堆,直到第一个节点
    Sink(i,n,r);
}
//堆排序
/*
1:构建初始堆
2:堆顶和最后一个节点交换,即r[1] 和r[n]交换,因为r[1]最大堆堆顶,必然为堆中最大的数,直接将最大的数放到最后,但是r[n]不一定是最小的数,所以调用sink(1,n-1)下沉方法,重新调整为堆
3:堆顶和最后一个节点r[n-1](因为r[n]已经是最大的数了,所以就不用再考虑了)交换即r[1] 和r[n-1],同理调用sink(1,n-2)下沉方法(因为r[n-1],r[n]已经已知是最大的数,和第二大的数,所以排序时不用再考虑)
4:循环n-1次(因为最后一个堆顶元素,已经没有可交换的了),得到有序序列
*/
void HeapSort(int n,vector<int> &r){
    while(n>1)
    {
      swap(r[0],r[n-1]);//第一个节点存储在了r[0],将第一个节点和最后一个节点交换
       n--;  
       Sink(1,n,r);//堆顶下沉,调整堆
    }
}
/*二叉搜索树的性质:

1)若它的左子树不为空,则左子树上所有节点都小于根节点的值。

2)若它的右子树不为空,则右子树上所有节点都大于根节点的值。

3)它的左右子树也分别为二叉搜索树。*/
//创建节点
void Create_Node(Btree &T,int x)
{  
    //在指针T处生成一个新的节点,内容为x
	T=new Bnode;
	T->data=x;
    下面两句话一定要加上,不要以为下面还要给他赋值,觉得加不加都行,血的教训!!
    T->lchild=NULL;
    T->rchild=NULL;
}
//插入法创建二叉搜索树
void insert(Btree &T, int value)//每次调用insert方法,只会插入一个值
{
	Btree  temp = T;//创建一个临时指针变量temp,保证T指针一直是指向根节点的
    //每次调用insert方法,都会有temp = T,则value就会从根节点开始一路比较,直到找到合适的位置
	while(true)//一旦创建节点成功则会break
    {
			if(value < temp->data)
            {
				if(temp->lchild == NULL)
                {
					Create_Node(temp->lchild,value);
					break ;
				}
                else
                {
					temp = temp->lchild;
				}
			}
            if(value > temp->data)
            {
				if(temp->rchild == NULL)
                {
					Create_Node(temp->rchild,value);
					break ;
				}
                else
                {
					temp = temp->rchild;
				}
			}
            if(value==temp->data)//不将和节点值相等的数据插入到搜索树中
            {
                count2++;//每当有重复值时,count2记录有几个重复的值,便于后面输出时最后一位的判断
                flag=false;//判断是否有和节点值相等的数,如果有,则直接break
                 break;
            }
             
	} 
}
//前序遍历  
void preorder (Btree &T,int size)
{
    if(T)//如果节点不为空才能不断调用preorder方法,如果节点为空则空操作
  {  
      if(flag==true)//当数组中没有重复时,flag==true,数组中每个值都插入到搜索树中
    {
        if(count1!=(size-1))//利用数组的长度size,和count1来限制二叉树的最后一个节点输出没有,
        //因为先输出元素,后count1加1,所以最后一个元素输出时,count=size-1
        cout<<T->data<<",";	
	    else 
        cout<<T->data;//最后一个元素的输出没有,
		count1++;//每次执行一次输出操作,count1加一
        preorder (T->lchild,size);//然后访问左子树(当左子树为空或者全部遍历完再下一步访问右子树)
        preorder (T->rchild,size);//当左子树为空或者全部遍历完后再访问右子树
    }
    // 当数组中有重复值时,flag==false,数组中和节点值相同的值不插入到搜索树中,所以最后一个节点是count1==(size-(count2+1))不输出,
    else{
         if(count1!=(size-(count2+1)))//利用数组的长度size,和count1来限制二叉树的最后一个节点输出没有,
        //因为先输出元素,后count1加1,所以最后一个元素输出时,count1=(size-(count2+1))
        cout<<T->data<<",";	
	    else 
        cout<<T->data;//最后一个元素的输出没有,
		count1++;//每次执行一次输出操作,count1加一
        preorder (T->lchild,size);//然后访问左子树(当左子树为空或者全部遍历完再下一步访问右子树)
        preorder (T->rchild,size);
    }
    
  }
}
//中序遍历
void inorder (Btree &T,int size)
{
    if(T)//如果节点不为空才能不断调用inorder方法,如果节点为空则空操作
    {   
        if(flag==true)//当数组中没有重复时,flag==true,数组中每个值都插入到搜索树中
    {
        inorder(T->lchild,size);//先访问左子树
        if(count1!=(size-1))//作用同上
        cout<<T->data<<",";	//当左子树为空或者已经全部遍历完后,再访问根
	    else 
        cout<<T->data;
		count1++;
        inorder(T->rchild,size);//然后访问右子树
    }
        //当数组中有重复值时,flag==false,数组中和节点值相同的值不插入到搜索树中,所以最后一个节点时count1==(size-(count2+1))不输出,
        else
        {
        inorder(T->lchild,size);//先访问左子树
        if(count1!=(size-(count2+1)))//作用同上
        cout<<T->data<<",";	//当左子树为空或者已经全部遍历完后,再访问根
	    else 
        cout<<T->data;
		count1++;
        inorder(T->rchild,size);//然后访问右子树
        }
    }
}
int main()
{  
    int n,value;
    Btree T;
cout<<"Input"<<endl;
vector<int> num;
    while(cin>>n)
    {
         if(n==0)
         break;
        num.push_back(n);
    }
    //因为后面要对num数组建立最大堆,和堆排序,会改变num数组的顺序,所以先用另一个数组把原始数组记录下来,方便后面根据原始数组建立搜索树
    vector<int> num2;
     for(int i=0;i<num.size();i++){
         num2.push_back(num[i]);
     }
    //建立最大堆
    CreatHeap(num.size(),num);
    //输出最大堆的层次顺序
    cout<<"Output"<<endl;
    for(int i=0;i<num.size();i++)
    {
     if(i!=(num.size()-1))
     cout<<num[i]<<",";
     else
     cout<<num[i];
    }
     cout<<endl;
     //堆排序
    HeapSort(num.size(),num);
    for(int i=0;i<num.size();i++)
    {
     if(i!=(num.size()-1))
     cout<<num[i]<<",";
     else
     cout<<num[i];
    }
    cout<<endl;
    //为了使T!=NULL,先建立根节点
    T=new Bnode;
	T->data = num2[0];
	T->lchild = NULL;
	T->rchild = NULL;
    //让数组中的每个元素插入到搜索树中
   for(int i=1;i<num2.size();i++)
   {       
       value=num2[i];
       insert(T, value);
   }
   //前序遍历
   preorder (T,num2.size());
   count1=0;
    cout<<endl;
    //中序遍历
    inorder (T,num2.size());
    count1=0;
    cout<<endl;
    cout<<"End";
    cout<<endl;
    return 0;
}











































欢迎大家指正!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

weixin_47373497

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

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

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

打赏作者

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

抵扣说明:

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

余额充值