排序之比较排序
1.冒泡排序
#include <stdio.h>
/*冒泡排序*/
/*设数组长度为N。
1.比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交换。
2.这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。
3.N=N-1,如果N不为0就重复前面二步,否则排序完成。*/
void swap(int * Num1,int * Num2)
{
int p=*Num1; // “*”是取值, “&”是取地址
*Num1=*Num2;
*Num2=p;
}
void BubbleSort(int Data[],int N)
{
int i,j;
for(i=0;i<N;i++) //总共需要遍历N次
for(j=1;j<N-i;j++) //遍历第i次时,从第N-i个元素开始,之后的元素均以排好队(如第一遍便利完成后,最大的元素在最后)
if(Data[j]<Data[j-1])
swap(&Data[j],&Data[j-1]); //传递地址进去进行交换
}
int main(void)
{
int Data[13]={ 81,94,11,96,12,35,17,95,28,58,41,75,15};
int i;
BubbleSort(Data,13);
for(i=0;i<13;i++)
printf("%d ",Data[i]);
return 0;
}
2.直接插入排序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*直接插入排序*/
/*每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,
直到全部记录插入完成为止。
设数组为a[0…n-1]。
1. 初始时,a[0]自成1个有序区,无序区为a[1..n-1]。令i=1
2. 将a[i]并入当前的有序区a[0…i-1]中形成a[0…i]的有序区间。
3. i++并重复第二步直到i==n-1。排序完成。*/
void swap(int * Num1,int * Num2)
{
int p=*Num1; // “*”是取值, “&”是取地址
*Num1=*Num2;
*Num2=p;
}
void Insertsort(int Data[],int N)
{
int i,j;
for(i=1;i<N;i++) //N个元素需要N次才能读入
{
for(j=i-1;j>=0 && Data[j]>Data[j+1];j--) //每读入一个元素就在之前排好序的数组中插入到合适的位置
swap(&Data[j],&Data[j+1]);
}
}
int main(void)
{
int Data[13]={ 81,94,11,96,12,35,17,95,28,58,41,75,15 };
int i;
Insertsort(Data,13);
for(i=0;i<13;i++)
printf("%d ",Data[i]);
return 0;
}
3.直接选择排序
#include <stdio.h>
/*直接选择排序*/
/*
将数据分为有序区和无序区,从无序区选一个最小的元素直接放到有序区的最后。
设数组为a[0…n-1]。
1. 初始时,数组全为无序区为a[0..n-1]。令i=0
2. 在无序区a[i…n-1]中选取一个最小的元素,将其与a[i]交换。交换之后a[0…i]就形成了一个有序区。
3. i++并重复第二步直到i==n-1。排序完成。
*/
void swap(int* a,int* b)
{
if(*a!= *b)
{
*a^=*b;
*b^=*a;
*a^=*b;
}
}
void Selectsort(int Data[],int N)
{
int i,j,MinIndex;
for(i=0;i<N;i++)
{
MinIndex = i;
for(j=i+1;j<N;j++)
{
if(Data[j]<Data[MinIndex]) //选择无序区的最小元素,类似冒泡排序
MinIndex = j;
}
swap(&Data[i],&Data[MinIndex]);
}
}
void display(int Data[],int N)
{
int i;
for(i=0;i<N;i++)
{
printf("%d ",Data[i]);
}
printf("\n");
}
int main(void)
{
int Data[13]={ 81,94,11,96,12,35,17,95,28,58,41,75,15 };
display(Data,13);
Selectsort(Data,13);
display(Data,13);
return 0;
}
4.希尔排序
#include <stdio.h>
/*希尔排序*/
/*先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)
分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序
(增量足够小)时,再对全体元素进行一次直接插入排序。*/
void swap(int * Num1,int * Num2)
{
int p=*Num1; // “*”是取值, “&”是取地址
*Num1=*Num2;
*Num2=p;
}
void Shellsort(int Data[],int N)
{
int i,j,Increament;
unsigned char Tmp;
for(Increament = N/2;Increament > 0;Increament /= 2) //分割子序列
{
for(i=Increament;i<N;i++) //分别直接插入
{
Tmp = Data[i];
for(j=i-Increament;j>=0 && Data[j] > Data[j+Increament];j-=Increament)
swap(&Data[j],&Data[j+Increament]);
}
}
for(i=0;i<N;i++)
printf("%d\n",Data[i]);
}
int main (void)
{
unsigned int Data[13]={81,94,11,96,12,35,17,95,28,58,41,75,15};
Shellsort(Data,13); //此处传入数组名
return 0;
}
5.堆排序
#include<stdio.h>
/*
堆排序:
①建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点,此处len是堆中元素的个数。
建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程,相当于o(h1)+o(h2)…+o(hlen/2)
其中h表示节点的深度,len/2表示节点的个数,这是一个求和的过程,结果是线性的O(n)。
②调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。
利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,
如果最大(小)值不是节点i而是它的一个孩子节点,那边交互节点i和该节点,然后再调用调整堆过程,
这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,
因为是沿着深度方向进行调整的。
③堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。
然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,
然后再将根节点取出,这样一直到所有节点都取出。堆排序过程的时间复杂度是O(nlgn)。
因为建堆的时间复杂度是O(n)(调用一次);调整堆的时间复杂度是lgn,调用了n-1次,
所以堆排序的时间复杂度是O(nlgn)
*/
void swap(int * Num1, int * Num2)
{
int p = *Num1; // “*”是取值, “&”是取地址
*Num1 = *Num2;
*Num2 = p;
}
void AdjustHeap(int* Data, int i,int num)
{
int Child=2*i+1; //左儿子的下标
int Tmp=Data[i]; //父节点
for (; Child < num;i=Child)//未越界
{
if (Child<num-1 && Data[Child] < Data[Child + 1]) //若有儿子大于父亲则调换父亲与最大儿子的位置
Child++; //左儿子大且大于父节点
//当左儿子小于右儿子时,需要将儿子的下标+1得到有儿子的下标
if (Data[Child] > Tmp) //右儿子最大且大于父节点
swap(&Data[i], &Data[Child]); //右儿子与父节点调换
else //父节点大于子节点,不用调换
break;
}
Data[i] = Tmp;
}
void HeapSort(int* Data, int num)
{
int i;
for (i = num / 2; i >= 0; i--)
AdjustHeap(Data, i, num);
for (i = num - 1; i > 0; i--)//删除总是发生在根Data[0]处,表中最后一个元素用来填补空缺
{
swap(&Data[0], &Data[i]);
AdjustHeap(Data, 0, i);
}
}
int main(void)
{
int Data[13] = { 81,94,11,96,12,35,17,95,28,58,41,75,15 };
int i;
HeapSort(Data, 13);
for (i = 0; i<13; i++)
printf("%d ", Data[i]);
return 0;
}
6.归并排序
#include<stdio.h>
#include<stdlib.h>
/*
归并排序:
比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;
否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,
直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。
归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,
再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。
*/
void Merge(int* Data, int* Array, int left, int cen, int right)//合并:第一个:Data[left~cen];第二个[cen+1~right]
{
int i = left; //第一个
int j = cen + 1;
int n = cen;
int m = right;
int k=0;
while (i <= n && j <= m) //选择小的先插入
{
if (Data[i] < Data[j])
Array[k++] = Data[i++];
else
Array[k++] = Data[j++];
}
while (i <= n) //剩下的直接插入
Array[k++] = Data[i++];
while (j <= m)
Array[k++] = Data[j++];
for (i = 0; i < k; i++)
Data[left + i] = Array[i];
}
void MSort(int* Data, int* Array, int left, int right)//递归排序
{
int cen;
if (left < right)
{
cen = (left+right) / 2;
MSort(Data,Array,left,cen);
MSort(Data, Array,cen+1,right);
Merge(Data, Array, left, cen, right);
}
}
void MergeSort(int* Data,int num)
{
int* Array ;
Array = (int*)malloc(num * sizeof(int));
if (Array == NULL)
printf("Error!!!\n");
else
{
MSort(Data, Array, 0, num - 1);
free(Array);
}
}
int main(void)
{
int Data[13] = { 81,94,11,96,12,35,17,95,28,58,41,75,15 };
int i;
MergeSort(Data, 13);
for (i = 0; i<13; i++)
printf("%d ", Data[i]);
return 0;
}
7.快速排序
/参考链接:http://developer.51cto.com/art/201403/430986.htm/
#include <stdio.h>
/*
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,
使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
*/
void swap(int * Num1, int * Num2)
{
int p = *Num1; // “*”是取值, “&”是取地址
*Num1 = *Num2;
*Num2 = p;
}
int Median3(int* Data, int left, int right)//三数中值分割法
{
int mid = (left + right) / 2;
if (Data[left] > Data[mid]) //先将left,mid,right顺序先排号
swap(&Data[left], &Data[mid]);
if (Data[left] > Data[right])
swap(&Data[left], &Data[right]);
if (Data[mid] > Data[right])
swap(&Data[mid], &Data[right]);
swap(&Data[mid], &Data[right - 1]);
return Data[right - 1];
}
void QuickSort(int* Data, int left,int right)
{
int i, j;
int key;
if (left + 3 <= right)
{
key = Median3(Data, left, right);
i = left;
j = right;
for (; ; )//排序核心
{
while (Data[i++] < key) {}//将比key小的数都放在key之前
while (Data[j--] > key) {}//将比key大的数都放在key之后
if (i < j) //若i处的数大于可以key,而j处的数小于key则交换两个数
swap(&Data[i], &Data[j]);
else
break;
}
swap(&Data[i], &Data[right - 1]); //将key归位
QuickSort(Data, left, i - 1);
QuickSort(Data, i + 1, right);
}
else
printf("Error!\n");
}
int main(void)
{
int Data[13] = { 81,94,11,96,12,35,17,95,28,58,41,75,15 };
int i;
QuickSort(Data, 0,13);
for (i = 0; i<13; i++)
printf("%d ", Data[i]);
return 0;
}