空间复杂度:
这里需要一个额外的空间存储当前临时的最小值,因此空间复杂度为O(1)。
算法稳定性:
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。
[cpp]
#include
void swap(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void SimpleSelectSort(int arr[],int len)
{
for (int i = 0; i < len; ++i)
{
int min_index = i;
for (int j = i + 1; j < len ; ++j)
{
if (arr[j] < arr[min_index])
{
min_index = j;
}
}
if (min_index != i)
{
swap(&arr[i],&arr[min_index]);
}
}
}
int main(int argc, char const *argv[])
{
int arr[10] = {9,8,7,6,5,4,3,2,1,0};
int len = sizeof(arr)/sizeof(int);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
SimpleSelectSort(arr,len);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
#include
void swap(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void SimpleSelectSort(int arr[],int len)
{
for (int i = 0; i < len; ++i)
{
int min_index = i;
for (int j = i + 1; j < len ; ++j)
{
if (arr[j] < arr[min_index])
{
min_index = j;
}
}
if (min_index != i)
{
swap(&arr[i],&arr[min_index]);
}
}
}
int main(int argc, char const *argv[])
{
int arr[10] = {9,8,7,6,5,4,3,2,1,0};
int len = sizeof(arr)/sizeof(int);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
SimpleSelectSort(arr,len);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
堆排序:
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素。
算法步骤:
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。 (1)用大根堆排序的基本思想 :
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区 。
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key 。
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。 …… 直到无序区只有一个元素为止。
(2)大根堆排序算法的基本操作:
① 初始化操作:将R[1..n]构造为初始堆。
② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。
注意:
①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。
②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止。
时间复杂度:
堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成。堆排序的最坏时间复杂度为O(nlogn)。堆序的平均性能较接近于最坏性能。由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
空间复杂度:
和上面算法一样,堆排序是就地排序,辅助空间为O(1)。
算法稳定性:
堆排序是不稳定的排序方法。
[cpp]
#include
void swap(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
/*堆调整*/
void HeapAdjust(int *arr,int i,int size){
int lchild = 2*i+1; //节点i的左子节点
int rchild = 2*(i+1); //节点i的右子节点
int max = i;
if (i <= size/2) //只对非叶节点进行调整
{
if (lchild < size && arr[lchild] > arr[max])
{
max = lchild;
}
if (rchild < size && arr[rchild] > arr[max])
{
max = rchild;
}
if (max != i)
{
swap(&arr[i],&arr[max]);
HeapAdjust(arr,max,size);//对调整过的max节点重新进行堆调整
}
}
}
/*建立无序大顶堆*/
void Buli