上次已经对几种排序算法进行了分析,接下来对剩余的几种排序算法进行分析,以及给出测试函数。
int *get_arr(int len)
{
//srand(time(NULL));
srand(100);
int *arr = (int *)malloc(sizeof(int)*len);
assert(arr != NULL);
for(int i = 0;i < len;i++)
{
arr[i] = rand();
}
return arr;
}
5,希尔排序
空间复杂度:O(1) 时间复杂度:O(n^1.35)/O(n^1.5)
思路:将待排序数组按照步长gap进行分组,然后将每组的元素利用直接插入排序的方法进行排序;每次将gap折半减小,循环上述操作;当gap=1时,利用直接插入,完成排序。
static void shell(int *arr,int len,int gap)
{
int i;
int j;
int tmp;
for(i = gap;i < len;i++)
{
tmp = arr[i];
for(j = i-gap;j>=0;j = j-gap)
{
if(tmp > arr[j])
{
break;
}
arr[j+gap] = arr[j];
}
arr[j+gap] = tmp;
}
}
void shell_sort(int *arr,int len)
{
shell(arr,len,3);
shell(arr,len,1);
}
6,快速排序
空间复杂度:O(logn) 时间复杂度:O(n*logn)
思路:挖坑填数+分治法。从序列当中选择一个基准数,在这里我们选择序列当中第一个数最为基准数,将序列当中的所有数依次遍历,比基准数大的位于其右侧,比基准数小的位于其左侧,重复步骤1.2,直到所有子集当中只有一个元素为止。
//递归形式快速排序
int partition(int *arr,int left,int right)
{
int tmp = arr[left];
while(left < right)
{
while(arr[right] >= tmp && left < right)
{
right--;
}
arr[left] = arr[right];
while(arr[left] <= tmp && left < right)
{
left++;
}
arr[right] = arr[left];
}
arr[left] = tmp;
return left;
}
void quick(int *arr,int left,int right)
{
if(left < right)
{
int base = partition(arr,left,right);
quick(arr,left,base-1);
quick(arr,base+1,right);
}
}
void quick_sort(int *arr,int len)
{
quick(arr,0,len-1);
}
//非递归形式快速排序
void quick_sort_stack(int *arr,int len)
{
int *stack = (int *)malloc(sizeof(int) * len * len);
assert(stack != NULL);
int top = 0;
stack[top++] = 0;
stack[top++] = len - 1;
int left = 0;
int right = 0;
int base = 0;
while(top != 0)
{
right = stack[--top];
left = stack[--top];
base = partition(arr,left,right);
if(left < base-1)
{
stack[top++] = left;
stack[top++] = base - 1;
}
if(right > base+1)
{
stack[top++] = base + 1;
stack[top++] = right;
}
}
free(stack);
}
7,堆排序
空间复杂度:O(1) 时间复杂度:O(n*logn)
堆:本质是一种数组对象。特别重要的一点性质:任意的叶子节点小于(或大于)它所有的父节点。对此,又分为大顶堆和小顶堆,大顶堆要求节点的元素都要大于其孩子,小顶堆要求节点元素都小于其左右孩子,两者对左右孩子的大小关系不做任何要求。
利用堆排序,就是基于大顶堆或者小顶堆的一种排序方法。
static void heap_adjust(int *arr,int start,int end)
{
int tmp = arr[start];
for(int i = 2*start+1;i <= end;i = 2*i+1)
{
if(i < end && arr[i]+1])
{
i++;
}
if(tmp > arr[i])
{
break;
}
else if(tmp else //tmp == arr[i]
{
;
}
start = i;
}
arr[start] = tmp;
}
void heap_sort(int *arr,int len)
{
for(int start = len/2-1;start >= 0;start--)
{
heap_adjust(arr,start,len-1);
}
swap(&arr[0],&arr[len-1]);
for(int k = len-1;k>0;k--)
{
heap_adjust(arr,0,k-1);
swap(&arr[0],&arr[k-1]);
}
}
8,归并排序
空间复杂度:O(n) 时间复杂度:O(n*logn)
思路:通过序列中各个元素的值,对排序的N个元素进行若干趟的“分配”与“收集”来实现排序。
分配:我们将L[i]中的元素取出,首先确定其个位上的数字,根据该数字分配到与之序号相同的桶中
收集:当序列中所有的元素都分配到对应的桶中,再按照顺序依次将桶中的元素收集形成新的一个待排序列L[ ]对新形成的序列L[]重复执行分配和收集元素中的十位、百位…直到分配完该序列中的最高位,则排序结束。
void meger(int *arr,int len,int gap)
{
int *buff = (int *)malloc(sizeof(int)*len);
int k = 0;
int L1 = 0;
int H1 = L1+gap-1;
int L2 = H1+1;
int H2 = L2+gap-1 < len ? L2+gap-1 : len-1;
while(L2 < len)
{
while(L1 <= H1 && L2 <= H2)
{
if(arr[L1] <= arr[L2])
{
buff[k++] = arr[L1++];
}
else if(arr[L1] > arr[L2])
{
buff[k++] = arr[L2++];
}
}
while(L1 <= H1)
{
buff[k++] = arr[L1++];
}
while(L2 <= H2)
{
buff[k++] = arr[L2++];
}
L1 = H2+1;
H1 = L1+gap-1;
L2 = H1+1;
H2 = L2+gap-1 < len ? L2+gap-1 : len-1;
}
while(L1 < len)
{
buff[k++] = arr[L1++];
}
for(int i = 0;i<len;i++)
{
arr[i] = buff[i];
}
free(buff);
}
void meger_sort(int *arr,int len)
{
for(int gap = 1;gap < len;gap = gap*2)
{
meger(arr,len,gap);
}
}
测试用例:
#include"sort.h"
#include
int main()
{
int arr[] = {13,34,32,21,13,45,30,56,43,31,11};
int len = sizeof(arr)/sizeof(arr[0]);
/*int *arr = get_arr(100000);
int len = 100000;
*/
//exchange_sort (arr,len);
//show(arr,len);
//bubble_sort(arr,len);
//show(arr,len);
//bubble_sort_ex(arr,len);
//show(arr,len);
//select_sort(arr,len);
quick_sort(arr,len);
//show(arr,len);
quick_sort_stack(arr,len);
//shell_sort(arr,len);
meger_sort(arr,len);
show(arr,len);
/*insert_sort_ex(arr,len);
show(arr,len);*/
return 0;
}
最后,对几种排序算法进行比较:
排序算法的分类
排序算法性能比较
若文章中或代码中存在问题,欢迎指正。