# C语言之各种排序法及核心思想（冒泡、鸡尾酒、选择、插入、二分法、希尔、堆、归并、快速）

#include <stdio.h>

void swap(int num[],int a, int b)
{
int tmp;
tmp = num[a];
num[a] = num[b];
num[b] = tmp;
}

void printfA(int *num,int len)
{
int i;
for(i = 0;i < len; i++)
{
printf("%4d",num[i]);
}
printf("\n");
}

//冒泡排序
int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
int i;
int j;
for(i = 0;i < len - 1; i++)
{
for(j = 0; j < len-1-i; j++)
{
if(num[j] > num[j+1])
swap(num,j,j+1);
}
}
printfA(num,len);
}

由于在排序过程中总是小数往前放，大数往后放，相当于气泡往上升，所以称作冒泡排序。


//鸡尾酒排序
int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
int i;
int left = 0;
int right = len - 1;
while(left < right)
{
for(i = left; i < right; i++)
{
if(num[i] > num[i+1])
swap(num,i,i+1);
}
right--;
for(i = right;i > left; i--)
{
if(num[i] < num[i-1])
swap(num,i,i-1);
}
left++;
}

printfA(num,len);
}



//选择排序
int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
int i;
int j;
int min;

for(i = 0;i < len-1; i++)
{
min = i;
for(j = i+1; j < len;j++)
{
if(num[min] > num[j])
{
min = j;
}
}
if(min != i)
swap(num,i,min);
}

printfA(num,len);
}



//插入排序
int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
int i;
int j;
int tmp;
for(i = 1; i < len; i++)
{
j = i-1;
tmp = num[i];
while(j > 0 && num[j] > tmp)
{
num[j + 1] = num[j];
j--;
}
num[j + 1] = tmp;
}

printfA(num,len);
}



//二分查找排序
int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
int left,right,mid,i,j;
int tmp;

for(i = 1; i < len; i++)
{
left = 0;
right = i-1;
tmp = num[i];

while(left <= right)
{
mid = (left+right)/2;
if(num[mid] > tmp)
right = mid - 1;
else
left = mid + 1;
}

for(j = i-1; j >= left; j--)
{
num[j+1] = num[j];
}
num[left] = tmp;
}

printfA(num,len);

return 0;
}



//希尔排序
int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
int i,tmp,j;
int d = len;

do
{
d = d / 3 + 1;
for(i = d; i < len; i++)
{
tmp = num[i];
j = i - d;
while(j > 0 && num[j] > tmp)
{
num[j+d] = num[j];
j -= d;
}
num[j + d] = tmp;
}
}while(d > 1);

printfA(num,len);

return 0;
}



//堆排序
void heapify(int num[],int i, int len)
{
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i;
if(left < len && num[left] > num[max])
max = left;
if(right < len && num[max] < num[right])
max = right;

if(max != i)
{
swap(num, i, max);
heapify(num, max, len);
}
}

void heapsort(int num[], int len)
{
int i;
for(i = len/2-1;i >= 0; i--)
{
heapify(num,i,len);
}
for(i = len-1;i > 0; i--)
{
swap(num,0,i);
len--;
heapify(num,0,len);
}
}

int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
heapsort(num,len);

printfA(num,len);

return 0;
}

其基本思想为(大顶堆)：
1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆，此堆为初始的无序区；
2)将堆顶元素R[1]与最后一个元素R[n]交换，此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
3)由于交换后新的堆顶R[1]可能违反堆的性质，因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆，然后再次将R[1]与无序区最后一个元素交换，得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1，则整个排序过程完成。


//归并排序
void merge(int *num,int left, int mid, int right, int *tmp)
{
int i = left;
int j = mid + 1;
int k = 0;
while(i <= mid && j <= right)
{
if(num[i] > num[j])
tmp[k++] = num[j++];
else
tmp[k++] = num[i++];
}

while(i <= mid)
tmp[k++] = num[i++];
while(j <= right)
tmp[k++] = num[j++];

k = 0;
for(i = left; i <= right; i++)
{
num[i] = tmp[k++];
}
}

void mergesort(int *num,int left, int right, int *tmp)
{
if(left >= right)
{
return;
}
int mid = (left + right)/2;

mergesort(num, left, mid, tmp);
mergesort(num, mid+1, right, tmp);

merge(num, left, mid, right, tmp);

}

int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
int tmp[10];
mergesort(num,0,len-1,tmp);

printfA(num,len);

return 0;
}



//快速排序法
int partition(int *num,int left, int right)
{
int pivot = num[right];
int index = left;
int i;
for(i = left; i < right; i++)
{
if(num[i] < pivot)
{
swap(num,i,index);
index++;
}
}
swap(num,index,right);
return index;
}

void qSort(int *num, int left, int right)
{
if(left < right)
{
int pivot = partition(num, left, right);

qSort(num, left, pivot-1);
qSort(num, pivot+1, right);
}
}

int main()
{
int num[10] = {0,9,8,7,6,5,4,3,2,1};
int len = sizeof(num)/sizeof(num[0]);
qSort(num,0,len-1);

printfA(num,len);

return 0;
}

假设要排序的数组是A[1]……A[N]，首先任意选取一个数据（通常选用第一个数据）作为关键数据，然后将所有比它小的数都放到它前面，所有比它大的数都放到它后面，这个过程称为一躺快速排序。一躺快速排序的算法是：
1）、设置两个变量I、J，排序开始的时候I：=1，J：=N；
2）以第一个数组元素作为关键数据，赋值给X，即X：=A[1]；
3）、从J开始向前搜索，即由后开始向前搜索（J：=J-1），找到第一个小于X的值，两者交换；
4）、从I开始向后搜索，即由前开始向后搜索（I：=I+1），找到第一个大于X的值，两者交换；
5）、重复第3、4步，直到I=J；