山东大学数据结构实验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;
}
欢迎大家指正!