1. 引言
本文主要讲解一些常见的排序算法。
2. 冒泡排序
冒泡排序是经过n-1趟子排序完成的,第i趟子排序从第1个数至第n-i个数,若第i个数比后一个数大(则升序,小则降序)则交换两数。
#include "ds.h"
#define N 8
// 将a中整数序列重新排列成自小至大有序的整数序列(起泡排序)
void bubble_sort(int a[],int n)
{
int i, j, t;
Status change;
for (i = n - 1, change = TRUE; i > 0 && change; --i)
{
change = FALSE;
for (j = 0; j < i; j++)
{
if (a[j] > a[j+1])
{
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
change = TRUE;
}
}
}
}
void print(int r[],int n)
{
int i;
for(i = 0; i < n; i++)
printf("%d ", r[i]);
printf("\n");
}
int main()
{
int d[N]={49,38,65,97,76,13,27,49};
printf("排序前:\n");
print(d,N);
bubble_sort(d,N);
printf("排序后:\n");
print(d,N);
}
3. 快速排序
快速排序(Quicksort)是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是: 1)设置两个变量I、J,排序开始的时候:I=0,J=N-1; 2)以第一个数组元素作为关键数据,赋值给 key ,即 key =A[0]; 3)从J开始向前搜索,即由后开始向前搜索(J=J-1即J--),找到第一个小于 key 的值A[j],A[j]与A[i]交换; 4)从I开始向后搜索,即由前开始向后搜索(I=I+1即I++),找到第一个大于 key 的A[i],A[i]与A[j]交换; 5)重复第3、4、5步,直到 I=J; (3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。找到并交换的时候i, j指针位置不变。另外当i=j这过程一定正好是i+或j-完成的最后另循环结束。)
#include "ds.h"
#define MAX_SIZE 20 // 一个用作示例的小顺序表的最大长度
typedef int KeyType; // 定义关键字类型为整型
typedef int InfoType; // 定义其它数据项的类型
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
struct RedType // 记录类型
{
KeyType key; // 关键字项
InfoType otherinfo; // 其它数据项,具体类型在主程中定义
};
struct SqList // 顺序表类型
{
RedType r[MAX_SIZE+1]; // r[0]闲置或用作哨兵单元
int length; // 顺序表长度
};
// 交换顺序表L中子表L.r[low..high]的记录,使枢轴记录到位,
// 并返回其所在位置,此时在它之前(后)的记录均不大(小)于它。算法10.6(a)
int Partition(SqList &L,int low,int high)
{
#if 1
KeyType pivotkey;
L.r[0] = L.r[low]; // 用子表的第一个记录作枢轴记录
pivotkey = L.r[low].key; // 枢轴记录关键字
while(low < high)
{ // 从表的两端交替地向中间扫描
while(low<high&&L.r[high].key>=pivotkey)
--high;
L.r[low]=L.r[high]; // 将比枢轴记录小的记录移到低端
while(low<high&&L.r[low].key<=pivotkey)
++low;
L.r[high]=L.r[low]; // 将比枢轴记录大的记录移到高端
}
L.r[low] = L.r[0]; // 枢轴记录到位
return low; // 返回枢轴位置
#else
RedType t;
KeyType pivotkey;
pivotkey = L.r[low].key; // 用子表的第一个记录作枢轴记录
while (low < high)
{
// 从表的两端交替地向中间扫描
while (low < high && L.r[high].key >= pivotkey)
--high;
// 将比枢轴记录小的记录交换到低端
t = L.r[low];
L.r[low] = L.r[high];
L.r[high] = t;
while (low < high && L.r[low].key <= pivotkey)
++low;
// 将比枢轴记录大的记录交换到高端
t = L.r[low];
L.r[low] = L.r[high];
L.r[high] = t;
}
return low; // 返回枢轴所在位置
#endif
}
// 快速排序的函数,包括算法10.7、10.8
void QSort(SqList &L, int low, int high)
{
// 对顺序表L中的子序列L.r[low..high]作快速排序。算法10.7
int pivotloc;
if (low < high) // 长度大于1
{
pivotloc = Partition(L, low, high); // 将L.r[low..high]一分为二
QSort(L, low, pivotloc - 1); // 对低子表递归排序,pivotloc是枢轴位置
QSort(L, pivotloc + 1, high); // 对高子表递归排序
}
}
// 对顺序表L作快速排序。
void QuickSort(SqList &L)
{
QSort(L, 1, L.length);
}
void print(SqList L)
{
int i;
for(i = 1; i <= L.length; i++)
printf("(%d,%d)", L.r[i].key, L.r[i].otherinfo);
printf("\n");
}
#define N 8
int main()
{
RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}};
SqList l;
int i;
for(i=0;i<N;i++)
l.r[i+1]=d[i];
l.length=N;
printf("排序前:\n");
print(l);
QuickSort(l);
printf("排序后:\n");
print(l);
}