排序算法之树形选择排序

树形选择排序又名锦标赛排序,算法思想与体育比赛类似, 首先将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;
}

    原文作者:排序算法
    原文地址: https://blog.csdn.net/wf131410000/article/details/47787749
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞