排序算法总结(2)——选择排序

接着上一篇文章《排序算法总结(1)——插入排序》的来。


排序主要分为插入排序、选择排序、交换排序、归并排序、计数(也有叫分配)排序。现在总结一下交换排序

二、选择排序

选择排序方案是一类常用的排序方案。其基本思想是在排序时每次选择最小或最大项,将其放入到适当位置上,依此类推。好比玩扑克牌时要将扑克从小到大排列,最常用的方法是在这套扑克牌中每次找出一张最大的牌,放入已选好的牌序列中,重复这个过程最终将完成扑克牌的有序排列。选择排序过程正是基于这样一种思想设计的。

1)直接选择排序

直接选择排序是最简单的选择排序方法,其基本步骤是(以升序排列为例)首先在一组数据对象V[i],V[i+1],....V[n-1]中选择具有最小关键码的对象,若它不是对象序列V[i],V[i+1],....V[n-1]中的第一个对象,则将它与这组对象中的第一个对象对调,然后在这组对象中剔除具有最小关键码的对象。在剩下的对象V[i+1],....,V[n-1]中重复执行上述步骤,直到剩余对象只有一个为止。显然在这个过程中,具有相同关键码的对象可能会颠倒次序。直接选择排序算法是一种不稳定的排序方法。算法的复杂度为O(n的平方)

源代码如下:

void SelectSort(int *a, int len)
{
	for (int i = 0; i < len; i ++)
	{
		int min = a[i];
		int pos = i;
		for (int j = i; j < len; j++)
		{
			if (a[j] < min)
			{
				min = a[j];
				pos = j;
			}
		}
		a[pos] = a[i];
		a[i] = min;
	}
}

2)堆排序

在计算机科学中,堆是一种以完全二叉树为基础的满足堆性质的特殊数据结构。所谓堆性质,即如果B是A的子结点,那么A中的关键码就大于等于B中的关键码。这意昧着结构中的数值最大的元素总是位于树的根部,并且这样的一个堆有时也被称为“最大堆”。相对地,如果关键码的比较关系与此相反,即B是A的子结点,A中的关键码小于等于B中的关键码,这样的一个堆被称为最小堆,其中数值最小的元素总是位于树的根部。



堆的建立:

一种建立堆的有效方法是将数据表中的元素顺序地填入一个完全二叉树中,然后通过所谓的“自上而下”(Top-Down)调整算法来使该完全二叉树满足堆性质。



可见自下而上的堆调整算法的核心思想是先将含有m个数据项的数据表按顺序存储进一棵完全二叉树中。然后再从某个分支结点 i 开始向下调整,如果此结点的左子结点 j 关键码小于右子结点 j+1 的关键码,那么就沿着结点 i 的左分支进行调整,其中 j=2*i+1。如果结点 i 的左子结点关键码大于右子结点的关键码,那么就沿着结点 i 的右分支进行调整。调整的方法是将该结点的关键码与其右子结点的关键码(或左子结点的关键码)进行比较,如果某个分支不满足堆性质就将该分支所在边两端的结点对调,从而把关键码较小的结点上浮。然后令 i=j, j=2*i+1,将比较和调整操作在局部范围内(子树内)下降一层,如果此时结点 i (注意此时l不再是起始结点了,而是下降一层后的结点)的关键码小于结点 j 的关键码,则不做调整,算法终止。如果情况相反,在调整后继续下降一层并做比较,直到该子树满足最小堆性质为止。最大堆的调整算法可由最小堆的调整算法类比推得。


堆操作:

向最小堆中插入一个元素 x 的过程就是不断自下向上调整新堆的过程。每次被插入的一个新结点总是被安插在最小堆的最后面,所谓的“最后面”指的是二叉树层次遍历次序的末尾。如图(a)所示,我们向原最小堆中插入一个元素8,将该元素续接在最小堆的末尾后,自下而上将其关键码.与其父结点的关键码相比较。因为8<15,所以将结点8和结点15对调,如图(b)所示。继续此过程,再经过一次调整后如图(c)所示,结点插入结果如图(d)所示。请读者注意堆的插入算法和建堆的调整算法之间的联系和区别



通常,最小堆的结点删除操作往往是指将其中具有最小关键码的数据项从堆中删除,这与优先级队列非常相似,也就是说删除操作只能在结构的一端进行。由于最小堆中关键码最小的元素总是位于堆顶,所以该删除操作实际上是将完全二叉树的根节点删除。当然如果一棵树的根结点被删除,那么该树的结构就势必被破坏。为了保持树形结构不被破坏,在删除其堆顶结点后,我们就将堆的最后一个结点(即完全二叉树层次遍历顺序下的末结点)取走用来填补缺失的堆顶元素,并将堆的实际元素个数减1。这时还要考虑使用最后一个元素取代堆顶元素后,如何维持堆的性质不被破坏。处理的方式很简单,就是使用堆的调正算法从堆顶向下进行调整,直到完全二叉树满足堆性质为止。

源代码:

//堆排序
#ifndef HEAPSORT_H
#define HEAPSORT_H
#include <vector>
using namespace std;
class HeapSort
{
private:
	int len;
	vector<int> list;
public:
	HeapSort(vector<int> _list, int _len);

	void heap_sort();
	void filterDown(int current, int last);
	void swap(int, int);
	void out();
};
#endif

#include "HeapSort.h"
#include <iostream>
using namespace std;

HeapSort::HeapSort(vector<int> _list, int _len)
{
	for (int i = 0; i < _len; i ++)
		list.push_back(_list[i]);
	this.len = _len;
}

//堆排序
void HeapSort::heap_sort()
{
	for (int i = (len-2)/2; i >= 0; i--)
		filterDown(i, len-1);
	for (i = len -1; i > 0; i--)
	{
		swap(0,i);
		filterDown(0,i-1);//不断调整堆为最大堆
	}
}

void HeapSort::filterDown(int current, int last)
{
	int child = 2*current+1;//child为current的子女位置
	int temp = list[current];//暂存子树的根节点
	while (child <= last)
	{
		if (child < last && list[child] < list[child+1])//让child指向两子女中的大者
			child++;
		if (temp >= list[child])
			break;//temp的关键码大则不做调整
		else//否则子女中的大者上移
		{
			list[current] = list[child];
			current = child;
			child = 2*child+1;//current下降到子女位置
		}
	}
	list[current] = temp;//temp里面暂存的元素放到合适的位置
}

void HeapSort::swap(int i, int j)
{
	int temp = list[i];
	list[i] = list[j];
	list[j] = temp;
}

void HeapSort::out()
{
	for (int i=0; i<len; i ++)
	{
		cout<< list[i]<<" ";
		if ((i+1)%18 == 0)
			cout<<endl;
	}
	cout<<endl;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值