1.希尔排序
1.1 算法
希尔排序(shell-sort)使用一个序列h1,h2,...,ht,叫做增量序列。只要h1 = 1,任何增量序列都是可行的。在使用增量hk的一趟排序之后,对于每一个i都有A[i] ≤ A[i + hk]。所有相隔hk的元素都被排序。此时称文件是hk-排序。直到h1排序完成,排序完成。
1.2 增量的序列
增量序列的选择极大的影响了希尔算法的效率。
好的增量序列有
(1)1,3,7,...,2^k - 1
(2){1,5,19,41,...}
该序列中的项或者是9*4^i - 9 * 2^i + 1,或者是4^i - 3 * 2^i + 1
1.3 实现
//
// main.c
// ShellSort
//
// Created by Wuyixin on 2017/6/2.
// Copyright © 2017年 Coding365. All rights reserved.
//
#include <stdio.h>
void shellSort(int a[],int n){
int j,i,increment,temp;
for (increment = n/2; increment > 0; increment /= 2) {
for (i = increment; i < n; i++) {
temp = a[i];
for (j = i ; j >= increment ; j -= increment){
if (temp < a[j - increment])
a[j] = a[j - increment];
else
break;
}
a[j] = temp;
}
}
}
int main(int argc, const char * argv[]) {
int a[] = {9,3,1,4,7,6,5,8,2};
shellSort(a, 9);
int i = 0;
while (i < 9)
printf("%d ",a[i++]);
return 0;
}
2.堆排序
2.1 算法
堆排序(heap-sort)是指利用堆积树(堆)这种
数据结构
所设计的一种
排序算法
,它是选择排序的一种。可以利用
数组
的特点快速定位指定索引的元素。
2.2 实现
//
// main.c
// HeapSort
//
// Created by Wuyixin on 2017/6/3.
// Copyright © 2017年 Coding365. All rights reserved.
//
#include <stdio.h>
typedef int ElemType;
#define LEFTCHILD(i) (2 * (i) + 1)
/* a是数组,n是数组大小,p是下滤的位置 */
void percolateDown(ElemType a[],int p,int n){
int child,parent,pvalue;
parent = p;
pvalue = a[p];
while ((child = LEFTCHILD(parent)) < n) {
/* 取左右孩子中的大者 */
if (child != n -1 && a[child] < a[child + 1])
child++;
/* 下滤 */
if (pvalue < a[child])
a[parent] = a[child];
/* 找到位置 */
else
break;
parent = child;
}
a[parent] = pvalue;
}
void swap(ElemType* a,ElemType* b){
ElemType temp = *a;
*a = *b;
*b = temp;
}
void heapSort(ElemType a[],int n){
int i;
/*构建堆*/
for (i = n/2; i >= 0; i--)
percolateDown(a, i, n);
/* DeleteMax */
for (i = n - 1; i > 0; i--) {
swap(&a[0], &a[i]);
percolateDown(a, 0, i);
}
}
int main(int argc, const char * argv[]) {
int a[] = {9,3,1,4,7,6,5,8,2,10,11,13,26,26};
heapSort(a, 14);
int i = 0;
while (i < 14)
printf("%d ",a[i++]);
return 0;
}
3.归并排序
3.1 算法
归并排序(merge-sort)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路
归并
。
归并过程为:比较a[i]和b[j]的大小,若a[i]≤b[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素b[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。
3.2 实现
//
// main.c
// MergeSort
//
// Created by Wuyixin on 2017/6/3.
// Copyright © 2017年 Coding365. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
void merge(ElemType a[],ElemType* tmpArr,int lPos,int rPos,int rEnd){
int lEnd,tmpPos,numElements;
lEnd = rPos -1;
numElements = rEnd - lPos + 1;
tmpPos = lPos;
while (lPos <= lEnd && rPos <= rEnd)
if (a[lPos] <= a[rPos])
tmpArr[tmpPos++] = a[lPos++];
else
tmpArr[tmpPos++] = a[rPos++];
while (lPos <= lEnd)
tmpArr[tmpPos++] = a[lPos++];
while (rPos <= rEnd)
tmpArr[tmpPos++] = a[rPos++];
for (lPos = 0;lPos < numElements;lPos++,rEnd--)
a[rEnd] = tmpArr[rEnd];
}
void msort(ElemType a[],ElemType* tmpArr,int left,int right){
int center;
if (left < right){
center = (left + right) / 2;
msort(a, tmpArr, left, center);
msort(a, tmpArr, center + 1, right);
merge(a, tmpArr, left, center + 1, right);
}
}
void mergeSort(ElemType a[],int n){
ElemType* tmpArr = (ElemType*)malloc(n * sizeof(ElemType));
if (tmpArr == NULL)
exit(EXIT_FAILURE);
msort(a, tmpArr, 0, n - 1);
free(tmpArr);
}
int main(int argc, const char * argv[]) {
int a[] = {9,3,1,4,7,6,5,8,2,10,11,13,26,26};
mergeSort(a, 14);
int i = 0;
while (i < 14)
printf("%d ",a[i++]);
return 0;
}
4.快速排序
4.1算法
快速排序(quick-sort)是对
冒泡排序
的一种改进。
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以
递归
进行,以此达到整个数据变成有序
序列
。
4.2实现
//
// main.c
// QuickSort
//
// Created by Wuyixin on 2017/6/3.
// Copyright © 2017年 Coding365. All rights reserved.
//
#include <stdio.h>
#define CUTOFF (3)
typedef int ElemType;
/* 交换a,b的值 */
void swap(ElemType* a,ElemType* b){
ElemType temp = *a;
*a = *b;
*b = temp;
}
/* 插入排序 */
void insertionSort(int a[],int left,int right){
int i,j,tmp;
for (i = left + 1; i <= right; i++) {
tmp = a[i];
for (j = i; j > left; j--) {
if (a[j - 1] > tmp)
a[j] = a[j - 1];
else
break;
}
a[j] = tmp;
}
}
/* 选择枢纽元 */
ElemType median(ElemType a[],int left,int right){
int center = (left + right) / 2;
if (a[left] > a[center])
swap(&a[left], &a[center]);
if (a[center] > a[right])
swap(&a[center], &a[right]);
if (a[left] > a[right])
swap(&a[left], &a[right]);
/* a[left] <= a[center] <= a[right] */
/* 由于a[right]肯定大于等于枢纽元a[center],因此比较可以从a[right - 1]开始 */
swap(&a[center], &a[right - 1]);/* 把枢纽元与参与比较的最后一个位置的元素对换 */
/* 返回枢纽元 */
return a[right - 1];
}
/* 核心算法 */
void Qsort(ElemType a[],int left,int right){
ElemType pivot;
int i,j;
if (left + CUTOFF > right){
pivot = median(a, left, right);
for (; ; ) {
/* 左边可以从left + 1开始比较,以为left上的元素肯定比pivot小 */
/* 右边可以从right - 1开始比较,以为right上的元素肯定比pivot大 */
i = left + 1;
j = right - 2;
/* 左边跳过比pivot小的数 */
while (a[i++] < pivot);
/* 右边跳过比pivot大的数 */
while (a[j--] > pivot);
/* 如果i还在j的左边,交换位置*/
if (i < j)
swap(&a[i], &a[j]);
else
break;
}
/* 将枢纽元调换回来 */
swap(&a[i], &a[right - 1]);
/* 此时枢纽元的左边都是比它小的元素,右边都是比它大的元素 */
Qsort(a, left, i - 1);
Qsort(a, i + 1, right);
}else
insertionSort(a,left,right);
}
/* 驱动函数 */
void quickSort(ElemType a[],int n){
Qsort(a, 0, n - 1);
}
int main(int argc, const char * argv[]) {
int a[] = {9,3,1,4,7,6,5,8,2,10,11,13,26,26,12,23,44,55,22,12,1};
quickSort(a, 21);
int i = 0;
while (i < 21)
printf("%d ",a[i++]);
return 0;
}