1.直接排序
思想:遍历数组元素,找到其中最小(大)元素,将其放在数组起始位置,再从剩余数组元素中继续寻找最小(大)元素,放在已排序序列末尾,重复至整条序列有序。
代码实现:
void select_sort(int* arr,int len)
{
if(arr == NULL || len<0)
return ;
int min = arr[0];
int min_index = 0;
for(int i=0;i<len-1;i++)
{
min = arr[i];
min_idex = i;
for(int j=0;j<len;j++)
{
if(min > arr[j])
{
min = arr[j];
min_index = j;
}
}
//交换最值与当前无序序列首元素位置
if(i != min_index)
{
int temp = arr[i];
arr[i] = arr[min_index];
arr[min_index] = temp;
}
}
}
优点:一轮比较只需要换一次位置,
缺点:效率慢,不稳定。
2.堆排序
基础:该排序方法基于“堆”的数据结构,而“堆”的本质是一个有序排列的完全二叉树,按照父节点键值与子节点键值的大小关系分为大根堆和小根堆。
思想:首先构建大根堆,将该数组(a1,a2……an)命名为无序区,然后将最大元素(a1)与无序区最后一个元素(an)进行位置互换,得到新的有序区(an)和无序区(a1,a2……an-1),且满足a[1,2…n-1]<=a[n],然后继续调整无序区成为新堆,重复以上算法,得到新的有序区与无序区,直到有序区的元素个数为n-1,则整个排序过程完成。
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
//堆调整算法
void HeapAdjust(int num[],int i,int length) {
//定义max保存以num[i]为根的最小堆中最大值的下标,初始值为i
int max=i;
//判断num[i]是否为根结点 (下标i<=length/2-1的结点都是根节点)
if(i<=length/2-1) {
//判断num[2*i+1]是否在堆内,若在,判断其是否大于num[max],若大于,将其下标2*i+1赋予给max
if((2*i+1)<length && num[2*i+1]>num[max]) {
max=2*i+1;
}
//判断num[2*(i+1)]是否在堆内,若在,判断其是否大于num[max],若大于,将其下标2*(i+1)赋予给max
if((2*(i+1))<length && num[2*(i+1)]>num[max]) {
max=2*(i+1);
}
//若i不等于max,则说明以num[i]为根的最小堆中num[max]是最大值,将num[max]与根结点num[i]交换位置
if(i!=max) {
num[i]=num[i]^num[max];
num[max]=num[i]^num[max];
num[i]=num[i]^num[max];
//交换后,为防止以num[max]为根结点的最小堆结构发生变换,再次调用堆调整算法
HeapAdjust(num,max,length);
}
}
}
//堆排序算法
void HeapSort(int num[],int length) {
int i;
//找到最后一个非叶子结点,先从最后一个非叶子结点组成的最小堆进行堆调整
for(i=length/2-1;i>=0;i--) //调用调整堆算法将数组从下往上调整为大根堆
HeapAdjust(num,i,length);
for(i=length-1;i>0;i--) {
//将数组第一个数和最后一个数换位置
num[i]=num[i]^num[0];
num[0]=num[i]^num[0];
num[i]=num[i]^num[0];
//继续调用调整堆算法,将剩余数据组成的堆从上往下调整为大根堆
HeapAdjust(num,0,i);
}
}
int main() {
int i;
int num[]={8,5,7,12,48,36,4};
HeapSort(num,sizeof(num)/sizeof(int));
for(i=0;i<sizeof(num)/sizeof(int);i++) {
printf("%d\t",num[i]);
}
printf("\n");
}
优点:高效,只需要O(1)的辅助空间。
缺点:不稳定,数据较少时不适合使用。
3.二者复杂度比较