初级版的冒泡排序算法是这样的:
void BubbleSort(Sqlist *L)//Sqlist是一个结构体,我下面会标明出来
{
int i,j;
for(i=1;ilength;i++){
for(j=i+1;jlength;j++){
if(L->r[i]>L->r[j]){//前者大于后者,即反序
swap(L,i,j);//交换值
}
}
}
}
/**顺序表结构体*/
#define MAXSIZE 10
typedef struct {
int r[MAXSIZE+1];//加1是为了让第一个元素的值从数组下标1开始算起。也就是说把r[0]用作临时变量
int length;
}Sqlist;
/**交换L中数组r的下标为i和j的元素*/
void swap(Sqlist *L,int i,int j){
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
void BubbleSort(Sqlist *L){
int i,j;
for(i=1;ilength;i++){//控制比较次数
for(j=L->length-1;j>=i;j--){//j从后往前循环
if(L->r[j]>L->r[j+1])//前者大于后者
{
swap(L,j,j+1);
}
}
}
}
#define FALSE = 0
#define TRUE = 1
void BubbleSort(Sqlist *L){
int i,j;
int flag = TRUE;//c语言文明用整形来表示,也可使用bool,C99增加的
for(i=1;ilength&&flag;i++){//若flag为true,则说明待排序列已经有序
flag = FALSE;//初始化为false
for(j=L->length-1;j>=i;j--){
if(L->r[j]>L->r[j+1]){
swap(L,j,j+1);
flag = TRUE;//有数据交换则为true
}
}
}
}
void SelectSort(Sqlist *L){
int i,j,min;
for(i=1;ilength;i++){
min = i; //将当前下标定义为最小值小标
for(j=i+1;j<=L->length;j++){
if(L->r[min] > L->r[j]){
min = j;//将此关键字的下标赋值给min
}
}
//内循环结束后,即一趟比较结束后,判断min是否等于i,否则说明最小值有改动,需交换
if(min != i){
swap(L,i,min);
}
}
}
void InsertSort(Sqlist *L){
int i,j;
for(i=2;i<=L->length;i++){
if(L->r[i] < L->r[i-1]){//后者比前者小,需将其插入有序子表
L->r[0] = L->r[i];//设置哨兵
for(j=i-1;L->r[j] > L->r[0];j--){
L->r[j+1] = L->r[j];//记录后移
}
L->r[j+1] = L->r[0];//插入到正确位置
}
}
}
void ShellSort(Sqlist *L){
int i,j;
int increment = L->length;//增量
do{
increment = increment/3+1;//增量序列
for(i=increment+1;ilength;i++){
//进行比较
if(L->r[i]r[i-increment]){
L->r[0]=L->r[i];//暂存在L->r[0]
for(j=i-increment;j>0&&L->r[0]r[j];j-=increment){//这里有些类似于直接插入排序
L->r[j+increment]=L->r[j];//记录后移
}
L->r[j+increment]=L->r[0];
}
}
}while(increment > 1)//终止条件是increment不大于1,即增量为1时就停止循环
}
//堆排序
void HeapSort(Sqlist *L){
int i;
for(i=L->length/2;i>0;i--)//把L中的r构建成一个大顶堆
{
HeapAdjust(L,i,L->length);//调整为大顶堆
}
for(i=L->length;i>1;i--){
swap(L,1,i);//将堆顶记录和当前未经过排序的子序列的最后一个记录交换
HeapAdjust(L,1,i-1);//将L->r[1...i-1]重新调整为大顶堆
}
}
void HeapAdjust(Sqlist *L ,int s,int m){
int temp,j;
temp = L->r[s];
for(j=2*s;j<=m;j*=2){// 沿关键字较大的孩子结点向下筛选,忘了二叉树性质的要回去看一下,不然你需要较多时间理解这段代码
if(jr[j]r[j+1])
++j; //j为关键字中较大的记录下标
if(temp>=L->r[j])
break;
L->r[s]=L->r[j];
s=j;
}
L->r[s] = temp;//插入
}
堆排序的时间复杂度,主要是消耗在初始构建堆和在重建堆时的反复筛选上。整个构建堆的时间复杂度为O(n),在正式排序时,第i次取堆顶记录重建堆需要用O(logi)的时间,并且需要取n-1次堆顶记录,因此,重建堆的时间复杂度为O(nlogn)。总体来说,堆排序的时间复杂度为O(nlogn)。由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度都为O(nlogn)。这在性能上显然要远远好过于冒泡、简单选择、直接插入的O(n^2)的时间复杂度了。空间复杂度值只需要一个用于交换的暂存单元。由于堆排序的比较与交换是跳跃式进行的,因此堆排序也是一种不稳定的排序方法,跟希尔排序同属于不稳定算法。
注:由于初始构建堆所需的比较次数较多,因此,它并不适合待排序序列个数较少的情况。
6、快速排序
快速排序请参见我的另外两篇博客《浅谈快速排序》、《快速排序优化分析》,这里我就不多说了。
7、归并排序
归并排序的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2(向上取整)个长度为2或1的有序字序列;再两两归并,
......,这样重复下去,直到得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。
看代码吧,
void MergeSort(SqList *L){
MSort(L->r,L->r,1,L->length);
}
void MSort(int SR[],int TR1[],int s,int t){
int m;
int TR2[MAXSIZE+1];
if(s == t)
TR1[s] = SR[s];
else{
m = (s+t)/2; // 将SR[s...t]平分为SR[s...m]和SR[m+1...t]
MSort(SR,TR2,s,m); //递归将SR[s...m]归并为有序的TR2[s...m]
MSort(SR,TR2,m+1,t);//递归将SR[m+1...t]归并为有序的TR2[m+1...t]
Merge(TR2,TR1,s,m,t);//将TR2[s...m]和TR2[m+1...t]归并到TR1[s...t]
}
}
void Merge(int SR[],int TR[],int i,int m,int n){
int j,k,l;
for(j=m+1,k=i;i<=m&&j<=n;k++){ //将SR中记录有小到大归并入TR
if(SR[i]