树形选择排序又名锦标赛排序,算法思想与体育比赛类似, 首先将n个数据元素两两分组,分别按关键字进行比较,得到n/2个比较的优胜者(关键字小者),作为第一步比较的结果保留下来, 然后对这n/2个数据元素再两两分组,分别按关键字进行比较,如此重复,直到选出一个关键字最小的数据元素为止。
树形选择排序构成的树是满二叉树。
算法步骤:
1.先获取需要排序的n个数据对象。
2.将n个数据对象用数组进行存储。
list(int ms):maxsize(ms),currsize(0) //初始化
{
vec = new node < T >[maxsize];
std::cout << "please input" << maxsize << " numbers" << std::endl;
T num;
int i = 0;
while (cin >> num)
{
if (i < maxsize)
{
vec[i].data = num;
++i;
++currsize;
}
}
}
这里只是构造函数,在构造函数里面进行存储需要排序的数据。
3.将n个数据对象构成满二叉树的外节点层,如果n不是2的幂次方,则添加数据元素构成满叉树外节点层。
4.将数组存储的数据填充外节点层,类似于二叉树的数组存储结构。
int nsize = 1;
while (nsize < currsize) //如果节点数为2的k次幂,则构成满二叉树,否则增加节点构成满二叉树
{
nsize = nsize * 2;
}
int treesize = 2*nsize - 1; //二叉树的结点数,nsize为叶子节点个数(最后一层)
node<T>* tree = new node < T >[treesize]; //构造满二叉树
int insize = nsize - 1; //内节点的个数
int j = 0;
for (int i =insize ; i < treesize; ++i) //将数据填充到二叉树
{
tree[i].index = i;
if (j < currsize)
{
tree[i].data = vec[j].data;
++j;
}
else //将增加的结点值赋为无穷大
{
tree[i].data = INT_MAX;
}
}
这里利用了满二叉树的一些性质:1.满二叉树中如果深度为k,那么有2^k-1个节点.
2.n0=n2+1 n0表示度为0的节点,n2表示度为2的节点,在满二叉树中没有度为1的节点。
5.进行数据比较,得出最小值。
//对二叉树进行扫描,使得二叉树头节点的值为最小
int k = insize;
while (k)
{
j = k; //先扫描最后一层,逐步逐步向上递进
while (j < 2 * k) //判断扫描有没有过界
{
if (tree[j] <= tree[j + 1])
{
tree[(j - 1) / 2] = tree[j];
}
else
{
tree[(j - 1) / 2] = tree[j+1];
}
j = j + 2;
}
k = (k - 1) / 2; //扫描下一层,直至k=0
}
6.对剩下n-1个数据进行处理。
//进行数据处理
for (int x = 0; x < currsize; ++x)
{
vec[x].data = tree[0].data; //将最小值传递给vec
tree[tree[0].index].data = INT_MAX; //将最小值置为无穷大,表示最小值已出局
Adjust(tree,tree[0].index); //对数组剩余数据进行处理,再排序,得到最小值
}
}
template<class T>
void list<T>::Adjust(node<T>* tree,int id) //对出现过最小值的分支进行数据更新,再次得到最小值
{
while(id)
{
if (id % 2 == 0) //最小值为右子树
{
if (tree[id]> tree[id - 1])
{
tree[id / 2 - 1] = tree[id - 1];
}
else
{
tree[id / 2 - 1] = tree[id ];
}
id = id / 2 - 1; //转到下一层
}
else //最小值为左子树
{
if (tree[id]> tree[id +1])
{
tree[(id-1)/2] = tree[id + 1];
}
else
{
tree[(id - 1)/ 2]= tree[id];
}
id = (id - 1) / 2;
}
}
}
附录完整程序:
头文件:
#ifndef SORT1_H
#define SORT1_H
#include<iostream>
template<class T> class list;
template<class T>
class node
{
friend class list<T>;
public:
node(): index(0){}
~node(){}
T getdata()
{
return data;
}
int operator>(node<T>& tep)
{
return this->data > tep.data;
}
int operator<(node<T>& tep)
{
return this->data < tep.data;
}
int operator>=(node<T>& tep)
{
return this->data >= tep.data;
}
int operator<=(node<T>& tep)
{
return this->data <= tep.data;
}
node<T>& operator=(node<T>& tep)
{
this->data = tep.data;
this->index = tep.index;
return *this;
}
private:
T data;
int index; //结点在满二叉树中的位置
};
template<class T>
class list
{
template<class T>
friend std::ostream& operator<<(std::ostream& out, list<T>& lst);
public:
list() :maxsize(0), currsize(0),vec(nullptr){}
~list(){}
list(int ms):maxsize(ms),currsize(0) //初始化
{
vec = new node < T >[maxsize];
std::cout << "please input" << maxsize << " numbers" << std::endl;
T num;
int i = 0;
while (cin >> num)
{
if (i < maxsize)
{
vec[i].data = num;
++i;
++currsize;
}
}
}
private:
node<T>* vec;
int maxsize;
int currsize;
public:
void TourSort(); //树形选择排序(锦标赛排序)
private:
void Adjust(node<T>* tree,int id);
};
template<class T>
void list<T>::TourSort()
{
int nsize = 1;
while (nsize < currsize) //如果节点数为2的k次幂,则构成满二叉树,否则增加节点构成满二叉树
{
nsize = nsize * 2;
}
int treesize = 2*nsize - 1; //二叉树的结点数,nsize为叶子节点个数(最后一层)
node<T>* tree = new node < T >[treesize]; //构造满二叉树
int insize = nsize - 1; //内节点的个数
int j = 0;
for (int i =insize ; i < treesize; ++i) //将数据填充到二叉树
{
tree[i].index = i;
if (j < currsize)
{
tree[i].data = vec[j].data;
++j;
}
else //将增加的结点值赋为无穷大
{
tree[i].data = INT_MAX;
}
}
//对二叉树进行扫描,使得二叉树头节点的值为最小
int k = insize;
while (k)
{
j = k; //先扫描最后一层,逐步逐步向上递进
while (j < 2 * k) //判断扫描有没有过界
{
if (tree[j] <= tree[j + 1])
{
tree[(j - 1) / 2] = tree[j];
}
else
{
tree[(j - 1) / 2] = tree[j+1];
}
j = j + 2;
}
k = (k - 1) / 2; //扫描下一层,直至k=0
}
//进行数据处理
for (int x = 0; x < currsize; ++x)
{
vec[x].data = tree[0].data; //将最小值传递给vec
tree[tree[0].index].data = INT_MAX; //将最小值置为无穷大,表示最小值已出局
Adjust(tree,tree[0].index); //对数组剩余数据进行处理,再排序,得到最小值
}
}
template<class T>
void list<T>::Adjust(node<T>* tree,int id) //对出现过最小值的分支进行数据更新,再次得到最小值
{
while(id)
{
if (id % 2 == 0) //最小值为右子树
{
if (tree[id]> tree[id - 1])
{
tree[id / 2 - 1] = tree[id - 1];
}
else
{
tree[id / 2 - 1] = tree[id ];
}
id = id / 2 - 1; //转到下一层
}
else //最小值为左子树
{
if (tree[id]> tree[id +1])
{
tree[(id-1)/2] = tree[id + 1];
}
else
{
tree[(id - 1)/ 2]= tree[id];
}
id = (id - 1) / 2;
}
}
}
template<class T>
std::ostream& operator<<(std::ostream& out, list<T>& lst)
{
for (int i = 0; i < lst.currsize; ++i)
{
out << lst.vec[i].getdata() << " ";
}
std::cout << std::endl;
return out;
}
#endif
主程序:
#include<iostream>
#include"sort1.h"
using namespace std;
int main()
{
list<int> ll(10);
ll.TourSort();
cout << ll << endl;
system("pause");
return 0;
}