排序算法(一)

288 阅读7分钟

数据准备

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;

//1.排序算法数据结构设计
//用于要排序数组个数最大值,可根据需要修改
#define MAXSIZE 10000
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);
    }

    
}

排序算法调用例子

#define N 9
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;
}