选择排序和堆排序

选择排序算法就是每一趟从待排序的记录中选出关键字最小(最大)的记录,顺序放在已排好序的子文件的最后(最前),直到全部记录排序完毕。常见的选择排序有直接选择排序(Selection Sort),堆排序(Heap Sort),平滑排序(Smooth Sort),笛卡尔树排序(Cartesian Sort),锦标赛排序(Tournament Sort),循环排序(Cycle)。下面介绍前两种:

(一)直接选择排序

最差时间复杂度:O(n^2)
最优时间复杂度:O(n^2)
平均时间复杂度:O(n^2)
稳定性:不稳定

直接选择排序(Selection Sort),这是一种简单直观的排序算法。它首先在未排序序列中找到最小(大)元素,存放到排序序列的其起始位置,然后再从剩余未排序的序列元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素排序完毕。

算法示意图:


实现代码:

[cpp]  view plain  copy
  1. void SelectSort(int *a, int len)  
  2. {  
  3.     for (int i=0; i<len-1; i++)  
  4.     {  
  5.         int k = i;  
  6.         int key = a[i];  
  7.         for (int j=i+1; j<len; j++)  
  8.         {  
  9.             if (a[j]<key)  
  10.             {  
  11.                 k = j;  
  12.                 key = a[j];  
  13.             }  
  14.         }  
  15.         if (k!=i)  
  16.             swap(a[i], a[k]);  
  17.     }  
  18. }  

(二)堆排序

最差时间复杂度:O(nlogn)
最优时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)
稳定性:不稳定

堆排序(Heap Sort),是利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。

通常堆是通过一维数组来实现的,在起始数组为0的情形中,对于节点i:
其左子节点的下标为 (2*i+1);
其右子节点的下标为 (2*i+2);
其父节点的下标为 floor((i-1)/2)。
在堆的数据结构中,堆中的最大值总是位于根节点。堆中定义一下三个操作:
1.最大堆调整(Max Heapify):在假定节点i的左右子节点为根的两颗二叉树都是最大堆的前提下,确保父节点大于子节点,否则下降原父节点,最终使以i为根的子树成为最大堆。
2.创建最大堆(Build Max Heap):将堆所有数据重新排序,对所有非叶子节点调用一次Max Heapify。

3.堆排序(Heap Sort):首先创建最大堆,然后依次将堆的根节点与末节点交换、剔除末节点、对根节点进行最大堆调整,直到堆中的节点数为1,排序结束。

算法示意图:


#include <iostream>
using namespace std;

void AdjustDown(int A[], int i, int len) 
{ 
	int temp = A[i]; // 暂存A[i] 

	for(int largest=2*i+1; largest<len; largest=2*largest+1) 
	{ 
		if(largest!=len-1 && A[largest+1]>A[largest]) 
			++largest;     // 如果右子结点大 
		if(temp < A[largest]) 
		{ 
			A[i] = A[largest]; 
			i = largest;     // 记录交换后的位置 
		} 
		else
			break; 
	} 
	A[i] = temp;  // 被筛选结点的值放入最终位置 
}
void BuildMaxHeap(int A[], int len) 
{ 
	for(int i=len/2-1; i>=0; --i) // 从i=n/2-1到0,反复调整堆 
		AdjustDown(A, i, len); 
} 
void HeapSort(int A[], int n) 
{ 
	BuildMaxHeap(A, n);    // 初始建堆 
	for(int i=n-1; i>0; --i) // n-1趟的交换和建堆过程  
	{ 
		// 输出最大的堆顶元素(和堆底元素交换) 
		A[0] = A[0]^A[i]; 
		A[i] = A[0]^A[i]; //写入排序后的元素值
		A[0] = A[0]^A[i]; 
		// 调整,把剩余的n-1个元素整理成堆 
		AdjustDown(A, 0, i);   //得到剩余的最大值
	} 
} 

int main() {
	int a[] = {3,2,5,6,1,9,0,7};
	HeapSort(a,8);
}


### 直接选择排序堆排序的比较 #### 1. 算法描述 直接选择排序是一种简单直观的排序算法,其核心思想是每次从未排序部分中找到最小值,并将其放到已排序部分的末尾。其实现过程如引用所述[^3],通过双重循环实现,时间复杂度为 \(O(N^2)\)。 堆排序是一种基于二叉堆数据结构的高效排序算法。它利用了堆的性质(大顶堆或小顶堆),首先将数组构建成一个堆,然后逐步将堆顶元素与末尾元素交换,并调整剩余部分以维持堆的性质。堆排序的时间复杂度为 \(O(N \log N)\)[^5]。 --- #### 2. 时间复杂度分析 - **直接选择排序**: 直接选择排序的时间复杂度始终为 \(O(N^2)\),无论输入数据是否有序。这是因为算法需要两层嵌套循环来完成排序操作。 - **堆排序**: 堆排序的时间复杂度为 \(O(N \log N)\)。建堆的过程可以通过从下到上的方式在 \(O(N)\) 时间内完成,而后续的调整交换操作需要 \(O(\log N)\) 的时间,总共执行 \(N\) 次,因此总复杂度为 \(O(N \log N)\)[^5]。 --- #### 3. 空间复杂度 - **直接选择排序**: 直接选择排序是一种原地排序算法,不需要额外的空间,因此空间复杂度为 \(O(1)\)[^3]。 - **堆排序**: 堆排序同样是一种原地排序算法,除了用于交换的临时变量外,不需要额外的空间,因此空间复杂度也为 \(O(1)\)[^5]。 --- #### 4. 实现代码 ##### 直接选择排序 ```python def select_sort(arr): n = len(arr) for i in range(n - 1): min_index = i for j in range(i + 1, n): if arr[j] < arr[min_index]: min_index = j if min_index != i: arr[i], arr[min_index] = arr[min_index], arr[i] ``` ##### 堆排序 ```python def heapify(arr, index, heap_size): left = 2 * index + 1 right = 2 * index + 2 largest = index if left < heap_size and arr[left] > arr[largest]: largest = left if right < heap_size and arr[right] > arr[largest]: largest = right if largest != index: arr[index], arr[largest] = arr[largest], arr[index] heapify(arr, largest, heap_size) def heap_sort(arr): n = len(arr) # 构建大顶堆 for i in range(n // 2 - 1, -1, -1): heapify(arr, i, n) # 逐个取堆顶元素 for i in range(n - 1, 0, -1): arr[0], arr[i] = arr[i], arr[0] heapify(arr, 0, i) ``` --- #### 5. 总结 - **直接选择排序**适合处理小规模数据,但其效率较低,尤其在大规模数据集上表现不佳。 - **堆排序**虽然实现稍复杂,但其高效的 \(O(N \log N)\) 时间复杂度使其更适合大规模数据排序任务。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值