数据准备
typedef int Status;
//1.排序算法数据结构设计
//用于要排序数组个数最大值,可根据需要修改
typedef struct
{
//用于存储要排序数组,r[0]用作哨兵或临时变量
int r[MAXSIZE+1];
//用于记录顺序表的长度
int length;
}SqList;
//2.排序常用交换函数实现
//交换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;
}
//3.数组打印
void print(SqList L)
{
int i;
for(i=1;i<L.length;i++)
printf("%d,",L.r[i]);
printf("%d",L.r[i]);
printf("\n");
}
冒泡排序初级版本
void BubbleSort0(SqList *L){
for (int i = 1; i<L->length; i++) {
for (int j = i+1; j<= L->length; j++) {
if (L->r[i] > L->r[j]) {
swap(L, i, j);
}
}
}
}
正宗冒泡排序
void BubbleSort(SqList *L){
for (int i = 1; i<L->length; i++) {
//注意:j是从后面往前循环的
for (int j=L->length-1; j>=i; j--) {
if (L->r[j] > L->r[j+1]) {
swap(L, j, j+1);
}
}
}
}
正宗冒泡排序优化
void BubbleSort2(SqList *L){
//记录是否交换了数据,默认交换
Status flag = TRUE;
for (int i=1; i<L->length && flag; i++) {
//先记录没有交换数据
flag = FALSE;
for (int j=L->length-1; j>=i; j--) {
if (L->r[j] > L->r[j+1]) {
swap(L, j, j+1);
//此时,发生了数据交换,标记
flag = TRUE;
}
}
}
// 只要内层循环有交换数据,则flag为true,说明后面的数据是无序的,需要继续排序;当flag为false时,说明后面的数据没有进行交换,此时后面的数据一定是有序的,循环已经无需再进行下去了。
}
选择排序
void SelectSort(SqList *L){
int i,j,min;
//
for (i=1; i<L->length; i++) {
//记录i对应的数据最小
min = i;
for (j=i+1; j<=L->length; j++) {
//到i后面的数据中找到数据最小的数据,记录其下标
if (L->r[min] > L->r[j]) {
min = j;
}
}
//交换i和最小的数据
if (min != i) {
swap(L, i, min);
}
}
}
插入排序
void InsertSort(SqList *L){
int i,j;
int temp = 0;
//默认第一个数据有序,所以从第二个数据开始
for (i=2; i<=L->length; i++) {
//当遍历到i时,i前面的数据一定是有序的
//所以当i小于i-1时,需要把i放到i前面的某个位置
if (L->r[i] < L->r[i-1]) {
//记录i的值
temp = L->r[i];
//将i前面的数据后移,找到i插入的位置
for (j = i-1; L->r[j] >temp; j--) {
//i前面的数据比i大,说明还没有找到,继续找
L->r[j+1] = L->r[j];//记录后移
}
//例如:1,3,4,5,6,2
//将i插入到i前面的一个合适位置,得到的i和i之前的数据是有序的
//这里j+1的原因是当3,2交换时,j指的是3的位置,当3,2交换完成后,执行了一次j--,此时1不小于2,循环结束,但这个时候j指向了1,但j实际需要的是1后面那个位置
L->r[j+1] = temp;
}
}
}
希尔排序
void shellSort(SqList *L){
int i,j;
int increment = L->length;
//如数据arr:0,9,1,5,8,3,7,4,6,2
//
do {
//得到增量序列,即首先将arr分成icrement组,
//如increment=4,则arr被分成如下组
//第一组:0,8,6,
//第二组:9,3,2
//第三组:1,7,
//第四组:5,4,
//分别对以上四组进行插入排序
//得到
//0,2,1,4,6,3,7,5,8,9
//再奖increment减小,变成2组
//第一组:0,1,6,7,8
//第二组:2,4,3,5,9
//分别对以上二组进行插入排序
//得到
//0,2,1,3,6,4,7,5,8,9
//得到如上相对有序的序列,然后进行插入排序
//当increment == 1时,下面的for实际就是在进行插入排序
//最后的结果为:0,1,2,3,4,5,6,7,8,9
increment = increment/3 + 1;
for (i= increment +1; i<= L->length; i++) {
if (L->r[i] < L->r[i-increment]) {
//记录i的数据
L->r[0] = L->r[i];
//记录后移,后移的过程,也是在找到i插入的合适的位置的过程
for (j=i-increment; j>0 && L->r[0] < L->r[j]; j -= increment) {
L->r[j+increment] = L->r[j];
}
//将i插入到合适的位置
L->r[j+increment] = L->r[0];
}
}
} while (increment>1);
}
堆排序
//堆排序的条件:把当前序列看成是一个完全二叉树的顺序存储情况
//大顶堆:二叉树的根结点对应的值一定大于左右子树的值,升序用大顶堆;
//小顶堆:二叉树的根结点对应的值一定小于左右子树的值,降序用小顶堆;
//将看成完全二叉树,并将其构造成大顶堆的完成二叉树,然后将堆顶数据放在最后面,最后面的数据不再处理,然后将除最后一个数据以外的数据重新构建大顶堆,以此类推
//构建大顶堆的方法
void HeapAjust(SqList *L,int s,int m){
int temp,j;
//记录下根结点的值
temp = L->r[s];
//将以s为根结点的树构建成大顶堆
//j 为什么从2*s 开始进行循环,以及它的递增条件为什么是j*2?
//因为这是颗完全二叉树,而s也是非叶子根结点. 所以它的左孩子一定是2*s,而右孩子则是2s+1;(二叉树性质5)
for (j = 2*s; j<= m; j *= 2) {
//判断j是否是最后一个结点, 并且找到左右孩子中最大的结点;
//如果左孩子小于右孩子,那么j++; 否则不自增1. 因为它本身就比右孩子大;
//这里是拿到s的左右子树中最大的一个
if (j<m && L->r[j] < L->r[j+1]) {
++j;//左子树比右子树小,所以我们要拿到右子树,
}
//比较s的值和s的左右子树谁大
if (temp > L->r[j]) {
//s的值比左右子树都大,没必要继续了
break;
}
//s的左右子树比s大,将其值给s
L->r[s] = L->r[j];
//记录,后面将原有的值存入j的位置
s = j;
}
//将temp的值给s = j
L->r[s] = temp;
}
void HeapSort(SqList *L){
int i = 0;
//将现在待排序的序列构建成一个大顶堆;
//将L构建成一个大顶堆
//i为什么是从length/2.因为在对大顶堆的调整其实是对完全二叉树的非叶子的根结点调整
//这里在构造全部数据的大顶堆
for (i= L->length/2; i>0; i--) {
HeapAjust(L, i, L->length);
}
//逐步将每个最大的值根结点与末尾元素进行交换,并且再调整成大顶堆
for (i=L->length; i>1; i--) {
//将堆顶记录与当前未经排序子序列的最后一个记录进行交换;
swap(L, 1, i);
//将局部数据重新调整成大顶堆
HeapAjust(L, 1, i-1);
}
}
排序算法调用例子
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
printf("Hello, 排序算法\n");
int i;
int d[N]={9,1,5,8,3,7,4,6,2};
//int d[N]={9,8,7,6,5,4,3,2,1};
//int d[N]={50,10,90,30,70,40,80,60,20};
SqList l0,l1,l2,l3,l4,l5,l6,l7,l8,l9,l10;
for(i=0;i<N;i++)
l0.r[i+1]=d[i];
l0.length=N;
l1=l2=l3=l4=l5=l6=l7=l8=l9=l10=l0;
printf("排序前:\n");
print(l0);
printf("\n");
//1.初级冒泡排序
printf("初级冒泡排序:\n");
BubbleSort0(&l0);
print(l0);
printf("\n");
//2.冒泡排序
printf("冒泡排序:\n");
BubbleSort(&l1);
print(l1);
printf("\n");
//3.冒泡排序优化
printf("冒泡排序(优化):\n");
BubbleSort2(&l2);
print(l2);
printf("\n");
//4.选择排序
printf("选择排序:\n");
SelectSort(&l3);
print(l3);
printf("\n");
//5.直接插入排序
printf("直接插入排序:\n");
InsertSort(&l4);
print(l4);
printf("\n");
//6.希尔排序
printf("希尔排序:\n");
shellSort(&l5);
print(l5);
printf("\n");
//7.堆排序
printf("堆排序:\n");
HeapSort(&l6);
print(l6);
printf("\n");
return 0;
}