排序算法——选择排序

       选择排序的基本思想:每一趟从待排序的元素中选出关键字最小(或最大)的元素,顺序放在已排好序的子表里,直到全部元素排序完毕。

1. 直接选择排序

/**
 * 选择排序
 *
 * 算法:直接选择排序(Straight Select Sort)
 * 输入:待排序元素的数组,待排序元素个数
 * 输出:
 * 原理:第i趟排序开始时,当前有序区为R[0..i-1],无序区为R[i..n-1],该趟排序从无序区中选出关键字最小的元素R[k],交换R[k]与R[i],形成新的有序区R[0..i]和无序区R[i+1..n-1]
 * 过程:
 *  1)初始化有序区为空,无序区为R[0..n-1]
 *  2)从无序区R[0..n-1]中选出关键字最小的元素并与R[0]交换,形成新的有序区R[0]和无序区R[1..n-1]
 *  3) ...
 *  4)形成新的有序区R[0..i-1]和无序区R[i..n-1]
 *  5)从无序区R[i..n-1]中选出关键字最小的元素并于R[i]交换,形成新的有序区R[0..i]和无序区R[i+1..n-1]
 *  6)重复上述操作,直到无序区中没有任何元素
 *  7) ...
 *  8)最终得到的R[0..n-1]中的元素递增排序
 *
 * 时间复杂度为O(n^2),空间复杂度为O(1),不稳定的排序方法
 */
void selectSort(RecType R[], int n)
{
	int i, j, k;
	RecType tmp;
	//做第i趟排序
	for (i = 0; i < n - 1; i++)
	{
		k = i;
		//在当前无序区R[i..n-1]中选key最小的R[k]
		for (j = i + 1; j < n; j++)
			if (R[j].key < R[k].key)
				k = j; //k记下目前找到的最小关键字所在的位置
		//交换R[i]与R[k]
		if (k != i)
		{
			tmp = R[i];
			R[i] = R[k];
			R[k] = tmp;
		}
	}
}

2. 堆排序

/**
 * 选择排序
 *
 * 算法:堆排序(Heap Sort)
 * 输入:待排序元素的数组(下标从1到n),待排序元素个数
 * 输出:
 * 定义:1) 小根堆:n个关键字序列K[1..n-1],满足K[i]<=K[2i]且K[i]<=K[2i+1]
		 2) 大根堆:n个关键字序列K[1..n-1],满足K[i]>=K[2i]且K[i]>=K[2i+1]
 * 原理:堆排序是一种树形选择排序方法,在排序过程中,R[1..n]被看做是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在关系,在当前无序区中选择关键字最小(或最大)的元素
 * 过程:
 *  1)针对R[1..n]构建初始堆,此时根节点R[1]为R[1..n]中关键字最大的元素
 *  2)交换R[1]与R[n]的位置
 *  3) 针对R[1..n-1]继续构建堆,此时根节点R[1]为R[1..n-1]中关键字最大的元素
 *  4)交换R[1]与R[n-1]的位置
 *  5)针对R[1..n-2]继续构建堆
 *  6)...
 *  7) 针对R[1..2]继续构建堆,此时根节点R[1]为R[1..2]中关键字最大的元素
 *  8) 交换R[1]与R[2]的位置
 *  8)最终得到的R[1..n]中的元素递增排序
 *
 * 时间复杂度为O(nlog2(n)),空间复杂度为O(1),不稳定的排序方法
 */
void heapSort(RecType R[], int n) //
{
	int i;
	RecType tmp;
	for (i = n / 2; i >= 1; i--) //循环建立初始堆
		shiftHeap(R, i, n);
	for (i = n; i >= 2; i--) //进行n-1趟堆排序,每一趟堆排序的元素个数减1
	{
		tmp = R[1]; //将最后一个元素与当前区间内R[1]对换
		R[1] = R[i];
		R[i] = tmp;
		shiftHeap(R, 1, i - 1); //筛选R[1]节点,得到i-1个节点的堆
	}
}

/**
 * 目的:构建R[low..high]的堆
 * 作用:大者“上浮”,小者被“筛选”下去
 * 原理:假设完全二叉树的某一个节点i,它的左子树和右子树已经是堆,接下来需要将R[2i].key与R[2i+1].key之中的最大者与R[i].key比较。
		 若R[i].key较小,则将其与最大孩子的关键字交换,这可能会破坏下一级的堆,于是继续采用上述方法构造下一级的堆,直到完全二叉树中节点i构成堆为止。
 * 过程:
 *	1) 初始化指针i指向R[low],将R[low]的左右孩子中关键字最大的孩子R[j]与R[low]交换,指针i指向交换的孩子R[j]
 *	2) 重复上述操作,直到j>high,即堆构建结束
 *
 */
void shiftHeap(RecType R[], int low, int high) //调整堆
{
	//R[j]是R[i]的左孩子
	int i = low, j = 2 * i;
	RecType tmp = R[i];
	while (j <= high)
	{
		if (j < high && R[j].key < R[j + 1].key) //若右孩子较大,把j指向右孩子
			j++;
		if (tmp.key < R[j].key)
		{
			//将R[j]调整到双亲节点位置上
			R[i] = R[j];
			//修改i和j值,以便继续向下筛选
			i = j;
			j = 2 * i;
		}
		else
			break; //筛选结束
	}
	//被筛选节点的值放入最终位置
	R[i] = tmp;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值