概述
按照是否使用外存,排序算法可分为内部排序和外部排序两种。
内部排序有如下几种常用的排序方法:
插入排序
直接插入排序
希尔排序
选择排序
简单选择排序
堆排序
交换排序
冒泡排序
快速排序
归并排序
插入排序
直接插入排序
该算法的基本思想可以描述为:在要排序的一组数中,假设前面(n-1)[n>=2]个数已经是排好了顺序的,现在要把第n个数字插到前面的有序数组中,使得这n个数也是排好顺序的。如此反复循环,直到全部都排好了顺序。
希尔排序
希尔排序又称为缩小增量排序,是直接插入排序的改进和优化。
其基本思想是先将序列分成若干子序列分别进行直接插入排序,待整个序列基本有序时再对整体进行一次直接插入排序。
算法特点是子序列不是简单的“逐段分割”,而是相邻某个“增量”的记录构成一个子序列。一般增量序列的选择直接使用上次的一半,例如整个序列长度为N,则第一次的增量序列可以选择为N/2。并注意,最后一个增量必须是1,这也是结束条件。
选择排序
简单选择排序
堆排序
当且仅当满足以下条件时,关键字序列K1—Kn可以称为堆:树中任一非叶子结点的关键字均不大于(不小于)其左右孩子节点的关键字。
用大顶堆排序的基本思想:
1) 先将输入的数字序列初始化成为大顶堆;
2) 将堆顶(也肯定是序列里最大的关键字)R[1]和序列最后一个关键字R[n]交换,由此得到新的无需区R[1]..R[n],而R[n]显然已经是有序区;
3) 调整R[1]..R[n]为有序堆,再将其堆顶与最末的元素交换,循环执行,直至所有元素都执行过排序为止。
交换排序
冒泡排序
冒泡算法的运作如下(从后往前):
1) 比较相邻元素,如果第一个比第二个大,就交换他们;
2) 对每一对相邻元素做如此操作,从开始第一对到结尾最后一对。执行完之后,最后一个元素应该是最大的数;
3) 针对所有的元素重复以上操作,除了最后一个;
4) 持续每次对越来越少的元素重复之前步骤,直到没有任何一对数字要比较;
快速排序
快速排序采用了分治的策略解决问题,分治法的核心思想是:将问题分解成若干个规模更小但结构与原问题相似的子问题。递归的解决这些子问题,最终将子问题的解组合成为原问题的解。
设当前待排序的无序区为R[low…high],利用分治法可以将快速排序的基本思想描述为:
1) 在数列中随机选取一个记录作为基准pivot(一般直接选取第一个),以此基准将当前序列划分为左右两个较小的子区间Rl和Rr,并使左区间中记录都小于pivot,右区间中值都大于pivot。此时pivot已经处在了正确的位置上,所以无需再次参加后续的排序。
2) 通过递归方法对左区间和右区间再次进行划分;
3) 递归返回时,序列已经成为有序,排序结束。
这里注意两点:
一般pivot会直接选择第一个记录,但随机选取的方法能够更好的照顾到算法对所有类型数列的时间消耗,对各种类型数列可以提高排序的效率;不论pivot选择哪里,总会有特殊情况导致算法耗时达到O(n2)的级别。
由于普遍认为20以内的数组排序,直接插入排序的效率是最高的,所以当数组长度小于20时,可以直接采用直接插入排序进行排序,而不是再次执行递归。
归并排序
归并排序是将两个(或以上)有序表合并成一个新的有序表,即把待排序的序列分成若干个有序的子序列,再把有序的子序列合并成整体有序的排序过程。
归并排序是建立在归并操作基础上的算法,该算法是采用分治法的一个典型应用。
归并排序的算法描述如下:
1) 申请空间,申请的大小应是两个已经有序的序列的长度之和,用来存放合并后的序列;
2) 设定两个指针,最初位置分别是两个已经排序序列的起始位置;
3) 比较两个指针指向的元素,选择相对小的放入合并后的空间,指针顺势移动到下一个元素;
4) 重复步骤3,直至某一个指针超出序列尾;
5) 将另一个序列剩下的所有元素直接复制到合并空间中;
代码实现
/*************************************************************************
> File Name: sort.h
> Author: Wujl
> Mail: wujl_0351@163.com
> Created Time: 2014年08月28日 星期四 15时01分15秒
************************************************************************/
#ifndef SORT_H
#define SORT_H
#define ARR_LEN 20 /*The length of the array which should be sorted*/
#define MAX_NUM ARR_LEN * 10 /*The number in this array should be limited. For example, array length is 10, the number in this array is in [0, 99]*/
#endif
sort.c文件,实现了以上七种排序算法。
/*************************************************************************
> File Name: sort.c
> Author: Wujl
> Mail: wujl_0351@163.com
> Created Time: 2014年08月28日 星期四 15时01分44秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "sort.h"
/*Create an array which length=ARR_LEN randomlly, this will be sort here.*/
void gen_rand_arr(int *arr, const int arr_len)
{
int i = 0;
for(; i < arr_len; i++)
{
*(arr + i) = rand() % MAX_NUM;
}
}
/*Create an array which is sorted to test sort algorithm time.*/
void gen_sorted_arr(int *arr, const int arr_len)
{
int i = 0;
for(; i < arr_len; i++)
{
*(arr + i) = i;
}
}
void gen_dis_sorted_arr(int *arr, const int arr_len)
{
int i = 0;
for(; i < arr_len; i++)
{
*(arr + i) = MAX_NUM - i;
}
}
void print_arr(int *arr, const int arr_len)
{
int i = 0;
for(; i < arr_len; i++)
{
printf("0x%04x\t", *(arr + i));
}
printf("\n");
}
/*Array dest and src has same length, and this function copy data from src to dest.*/
void copy_arr(int *dest, int *src, const int arr_len)
{
int i = 0;
while(i < arr_len)
{
*(dest + i) = *(src + i);
i++;
}
}
/*I just set a rule here: from small number to big number is the sorted array in my program.*/
int is_sorted_arr(int *arr, const int arr_len)
{
int i = 0;
for(; i < arr_len - 1; i++)
{
if(*(arr + i) > *(arr + i + 1))
{
return -1;
}
}
return 0;
}
void swap(int *num1, int *num2)
{
int temp = *num1;
*num1 = *num2;
*num2 = temp;
}
void direct_insert_sort(int *arr, const int arr_len)
{
int i = 0, j = 0, temp = 0;
for(i = 1; i < arr_len; i++)
{
for(j = i - 1; j >= 0; j--)
{
if(*(arr + j) > *(arr + j + 1))
{
swap(arr + j, arr + j + 1);
}
else
{
break;
}
}
}
}
void hash_sort(int *arr, const int arr_len)
{
int delta = arr_len / 2;
int i = 0, j = 0, temp = 0;
for(delta = arr_len / 2; delta >= 1; delta /= 2)
{
for(i = delta; i < arr_len; i++)
{
for(j = i - delta; j >= 0 && *(arr + j) > *(arr + j + delta); j -= delta)
{
swap(arr + j, arr + j + delta);
}
}
}
}
void select_sort(int *arr, const int arr_len)
{
int i = 0, j = 0;
int min_idx = 0;
for(i = 0; i < arr_len; i++)
{
min_idx = i;
for(j = i + 1; j < arr_len; j++)
{
if(*(arr + min_idx) > *(arr + j))
{
min_idx = j;
}
}
swap(arr + i, arr + min_idx);
}
}
void quick_sort(int *arr, const int l, const int r)
{
if(l < r)
{
int i = l, j = r, x = *(arr + l);
while(i < j)
{
while(i < j && *(arr + j) > x)
{
j--;
}
if(i < j)
{
*(arr + i) = *(arr + j);
i++;
}
while(i < j && *(arr + i) < x)
{
i++;
}
if(i < j)
{
*(arr + j) = *(arr + i);
j--;
}
}
*(arr + i) = x;
quick_sort(arr, l, i - 1);
quick_sort(arr, i + 1, r);
}
}
void bubble_sort(int *arr, const int arr_len)
{
int i, j;
for(i = arr_len - 1; i > 1; i--)
{
for(j = 0; j < i; j++)
{
if(*(arr + j) > *(arr + j + 1))
{
swap(arr + j, arr + j + 1);
}
}
}
}
/*============================Heap sort start===============================*/
void adjust_add(int *, int);
void create_heap(int *arr, const int arr_len)
{
int i = 1;
for(; i < arr_len; i++)
{
adjust_add(arr, i);
}
}
void adjust_add(int *arr, int idx)
{
int father_idx = (idx - 1) / 2;
while(father_idx >= 0)
{
if(*(arr + father_idx) < *(arr + idx))
{
swap(arr + father_idx, arr + idx);
idx = father_idx;
father_idx = (idx - 1) / 2;
}
else
{
break;
}
}
}
void adjust_del(int *arr, int end_idx)
{
int father_idx = 0;
int max_child_idx = father_idx * 2 + 1;
while(max_child_idx <= end_idx)
{
if((max_child_idx + 1) <= end_idx && *(arr + max_child_idx) < *(arr + max_child_idx + 1))
max_child_idx++;
if(*(arr + father_idx) > *(arr + max_child_idx))
{
break;
}
else
{
swap(arr + father_idx, arr + max_child_idx);
father_idx = max_child_idx;
max_child_idx = max_child_idx * 2 + 1;
}
}
}
void heap_sort(int *arr, const int arr_len)
{
create_heap(arr, arr_len);
int end_idx = arr_len - 1;
while(end_idx > 0)
{
swap(arr, arr + end_idx);
end_idx--;
adjust_del(arr, end_idx);
}
}
/*========================Heap sort end============================================*/
/*========================Merge sort start==========================================*/
void merge_array(int *arr, int first, int mid, int last, int *temp)
{
int i = first, j = mid + 1, k = 0;
while(i <= mid && j <= last)
{
if(*(arr + i) < *(arr + j))
{
*(temp + (k++)) = *(arr + (i++));
}
else
{
*(temp + (k++)) = *(arr + (j++));
}
}
while(i <= mid)
{
*(temp + (k++)) = *(arr + (i++));
}
while(j <= last)
{
*(temp + (k++)) = *(arr + (j++));
}
for(i = 0; i < k; i++)
{
*(arr + i + first) = *(temp + i);
}
}
void merge_sort_step(int *arr, int first, int last, int *temp)
{
if(first < last)
{
int mid = (first + last) / 2;
merge_sort_step(arr, first, mid, temp);
merge_sort_step(arr, mid + 1, last, temp);
merge_array(arr, first, mid, last, temp);
}
}
void merge_sort(int *arr, const int arr_len)
{
int *temp = (int *)malloc(arr_len * sizeof(int));
if(NULL == temp)
{
return ;
}
merge_sort_step(arr, 0, arr_len - 1, temp);
free(temp);
temp = NULL;
}
test.c文件,对sort.c文件中的各个函数进行了单元测试,并对各个排序算法进行简单的排序测试。
/*************************************************************************
> File Name: test.c
> Author: Wujl
> Mail: wujl_0351@163.com
> Created Time: 2014年08月28日 星期四 15时02分34秒
************************************************************************/
#include <stdio.h>
#include <time.h>
#include "sort.h"
void test_gen_arr()
{
int arr[ARR_LEN];
printf("Random array will be generated now:\n");
gen_rand_arr(arr, ARR_LEN);
print_arr(arr, ARR_LEN);
printf("\nSorted array generated now.\n");
gen_sorted_arr(arr, ARR_LEN);
print_arr(arr, ARR_LEN);
printf("\nDis_sorted array generated now.\n");
gen_dis_sorted_arr(arr, ARR_LEN);
print_arr(arr, ARR_LEN);
}
void test_copy_arr()
{
int arr[ARR_LEN];
printf("Random array will be generated now:\n");
gen_rand_arr(arr, ARR_LEN);
print_arr(arr, ARR_LEN);
int dest[ARR_LEN];
copy_arr(dest, arr, ARR_LEN);
printf("Copied array is:\n");
print_arr(dest, ARR_LEN);
}
void test_is_sorted_arr()
{
int arr[ARR_LEN];
printf("Random array will be generated now:\n");
gen_rand_arr(arr, ARR_LEN);
print_arr(arr, ARR_LEN);
int is_sorted = is_sorted_arr(arr, ARR_LEN);
if(0 == is_sorted)
{
printf("This is a sorted array.\n");
}
else
{
printf("Not a sorted array!\n");
}
printf("\nSorted array generated now.\n");
gen_sorted_arr(arr, ARR_LEN);
print_arr(arr, ARR_LEN);
is_sorted = is_sorted_arr(arr, ARR_LEN);
if(0 == is_sorted)
{
printf("This is a sorted array.\n");
}
else
{
printf("Not a sorted array!\n");
}
printf("\nDis_sorted array generated now.\n");
gen_dis_sorted_arr(arr, ARR_LEN);
print_arr(arr, ARR_LEN);
is_sorted = is_sorted_arr(arr, ARR_LEN);
if(0 == is_sorted)
{
printf("This is a sorted array.\n");
}
else
{
printf("Not a sorted array!\n");
}
}
void test_direct_insert_sort(void)
{
int arr[ARR_LEN];
gen_rand_arr(arr, ARR_LEN);
printf("Array is:\n");
print_arr(arr, ARR_LEN);
direct_insert_sort(arr, ARR_LEN);
printf("After direct insert sorting, array is:\n");
print_arr(arr, ARR_LEN);
if(0 == is_sorted_arr(arr, ARR_LEN))
{
printf("This is a sorted array.\n");
}
else
{
printf("!!!After direct insert sort, not sorted!!!\n");
}
}
void test_hash_sort(void)
{
int arr[ARR_LEN];
gen_rand_arr(arr, ARR_LEN);
printf("Array is:\n");
print_arr(arr, ARR_LEN);
hash_sort(arr, ARR_LEN);
printf("After hash sort, array is:\n");
print_arr(arr, ARR_LEN);
if(0 == is_sorted_arr(arr, ARR_LEN))
{
printf("This is a sorted array.\n");
}
else
{
printf("!!!After direct insert sort, not sorted!!!\n");
}
}
void test_select_sort(void)
{
int arr[ARR_LEN];
gen_rand_arr(arr, ARR_LEN);
printf("Array is:\n");
print_arr(arr, ARR_LEN);
select_sort(arr, ARR_LEN);
printf("After select sort, array is:\n");
print_arr(arr, ARR_LEN);
if(0 == is_sorted_arr(arr, ARR_LEN))
{
printf("This is a sorted array.\n");
}
else
{
printf("!!!After direct insert sort, not sorted!!!\n");
}
}
void test_quick_sort(void)
{
int arr[ARR_LEN];
gen_rand_arr(arr, ARR_LEN);
printf("Array is:\n");
print_arr(arr, ARR_LEN);
quick_sort(arr, 0, ARR_LEN - 1);
printf("After quick_sort, array is:\n");
print_arr(arr, ARR_LEN);
if(0 == is_sorted_arr(arr, ARR_LEN))
{
printf("This is a sorted array.\n");
}
else
{
printf("!!!After direct insert sort, not sorted!!!\n");
}
}
void test_bubble_sort(void)
{
int arr[ARR_LEN];
gen_rand_arr(arr, ARR_LEN);
printf("Array is:\n");
print_arr(arr, ARR_LEN);
bubble_sort(arr, ARR_LEN);
printf("After bubble sort, array is:\n");
print_arr(arr, ARR_LEN);
if(0 == is_sorted_arr(arr, ARR_LEN))
{
printf("This is a sorted array.\n");
}
else
{
printf("!!!After bubble sort, not sorted!!!\n");
}
}
void test_heap_sort(void)
{
// int arr[10] = {
// 57, 68, 59, 52, 73, 64, 26, 89, 96, 34
// };
// heap_sort(arr, 10);
// print_arr(arr, 10);
int arr[ARR_LEN];
gen_rand_arr(arr, ARR_LEN);
printf("Array is:\n");
print_arr(arr, ARR_LEN);
heap_sort(arr, ARR_LEN);
printf("After heap sort, array is:\n");
print_arr(arr, ARR_LEN);
if(0 == is_sorted_arr(arr, ARR_LEN))
{
printf("This is a sorted array.\n");
}
else
{
printf("!!!After heap sort, not sorted!!!\n");
}
}
void test_merge_sort(void)
{
int arr[ARR_LEN];
gen_rand_arr(arr, ARR_LEN);
printf("Array is:\n");
print_arr(arr, ARR_LEN);
merge_sort(arr, ARR_LEN);
printf("After merge sort, array is:\n");
print_arr(arr, ARR_LEN);
if(0 == is_sorted_arr(arr, ARR_LEN))
{
printf("This is a sorted array.\n");
}
else
{
printf("!!!After merge sort, not sorted!!!\n");
}
}
int main(int argc, unsigned char **argv)
{
srand((unsigned char)time(NULL));
// test_gen_arr();
// test_copy_arr();
// test_is_sorted_arr();
// test_direct_insert_sort();
// test_hash_sort();
// test_select_sort();
// test_quick_sort();
// test_bubble_sort();
// test_heap_sort();
test_merge_sort();
return 0;
}
Makefile文件用于生成可执行目标文件,这里定义为sort.elf。
CC = gcc
TARGET = sort.elf
SRC = sort.c test.c
all:
$(CC) -o $(TARGET) $(SRC)
clean:
rm -rf *~ $(TARGET)
经简单测试,该程序可以对随机生成的数组进行排序(默认排列成由小到大的数组)。