排序算法之选择排序( 选择排序 & 堆排序 )

  • 选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法

   【直接选择排序】

  • 在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素
  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中 的最后一个(第一个)元素交换
  • 在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中, 重复上述步骤,直到集合剩余1个元素

代码如下 ( 下面代码是一次循环同时挑选出最大和最小数, 并将其与左右交换 ): 

//选择排序
void SelectionSort(int *a, int len)
{
	int left = 0, right = len - 1;
	while (left < right){
		//max记录最大数的下标,min记录最小数的下标
		int max = left, min = left;
		for (int i = left; i <= right; i++){
			if (a[i]>a[max])
				max = i;
			if (a[i] < a[min])
				min = i;
		}
		Swap(&a[min], &a[left]);
		//如果最大数的下标在为left,证明要交换的最大数已经被
		//换到min小标所表示的位置,只需要将right和min位置交换即可
		if (max == left)
			Swap(&a[min], &a[right]);
		else
			Swap(&a[max], &a[right]);
		left++, right--;
	}
}
  • 堆排序 (Heap sort) 是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

    创建堆:升序—>大堆,降序—>小堆

    

执行如下步骤,直到数组为空

  1. 把堆顶array[0]元素和当前最堆的最后一个元素交换
  2. 堆元素个数减1
  3. 由于第1步后根节点不再满足最堆定义,向下调整根结点
  • 把一棵完全二叉树调整为堆,以及每次将堆顶元素交换后 进行调整的时间复杂度均为O(log2^n),所以堆排序的时 间复杂度为:O(N*log2^n)  堆排序是一种不稳定的排序算法

代码如下 :

//向下调整
void AdjustDown(int *a, int parent, int len)
{
	assert(a);
	while (parent <= len / 2 - 1){
                //取父节点的左孩子
		int child = parent * 2 + 1;
                //取左右子树中最大值
		if (child + 1 < len)
			child = a[child] > a[child + 1] ? child : child + 1;
                //如果孩子节点大于父节点,则交换
		if (a[child] > a[parent])
			Swap(&a[child], &a[parent]);
                //更新父节点,继续向下调整
		parent = parent + 1;
	}
}
//堆排序
void HeapSort(int *a, int len)
{
	assert(a);
        //从底向上依次向下调整
	for (int parent = len / 2 - 1; parent >= 0; parent--)
		AdjustDown(a, parent, len);
	int i = len-1;
        //将堆顶元素和数组最后一个元素交换,并且重新向下调整
	for (; i > 0 ; i--){
		Swap(&a[0], &a[i]);
		AdjustDown(a, 0, i);
	}
}

完整代码如下 : 

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//交换数据
void Swap(int *m, int *n)
{
	int tmp = *m;
	*m = *n;
	*n = tmp;
}
//选择排序
void SelectionSort(int *a, int len)
{
	int left = 0, right = len - 1;
	while (left < right){
		//max记录最大数的下标,min记录最小数的下标
		int max = left, min = left;
		for (int i = left; i <= right; i++){
			if (a[i]>a[max])
				max = i;
			if (a[i] < a[min])
				min = i;
		}
		Swap(&a[min], &a[left]);
		//如果最大数的下标在为left,证明要交换的最大数已经被
		//换到min小标所表示的位置,只需要将right和min位置交换即可
		if (max == left)
			Swap(&a[min], &a[right]);
		else
			Swap(&a[max], &a[right]);
		left++, right--;
	}
}
//向下调整
void AdjustDown(int *a, int parent, int len)
{
	assert(a);
	while (parent <= len / 2 - 1){
		int child = parent * 2 + 1;
		if (child + 1 < len)
			child = a[child] > a[child + 1] ? child : child + 1;
		if (a[child] > a[parent])
			Swap(&a[child], &a[parent]);
		parent = parent + 1;
	}
}
//堆排序
void HeapSort(int *a, int len)
{
	assert(a);
	for (int parent = len / 2 - 1; parent >= 0; parent--)
		AdjustDown(a, parent, len);
	int i = len-1;
	for (; i > 0 ; i--){
		Swap(&a[0], &a[i]);
		AdjustDown(a, 0, i);
	}
}
//打印数组
void PrintArray(int *a, int len)
{
	assert(a);
	for (int i = 0; i < len; i++)
		printf("%d ", a[i]);
	printf("\n");
}
int main()
{
	int a[] = { 58, 25, 49, 25, 16, 34 };
	SelectionSort(a, sizeof(a) / sizeof(int));
	//HeapSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ds19980228/article/details/82851785