C语言排序算法-冒泡、选择、插入、希尔、堆、归并、快速、拓扑

目录结构

C语言排序算法-冒泡、选择、插入、希尔、堆、归并、快速、拓扑_第1张图片

排序要用到的结构和函数

Prelimitation.h

#ifndef SORT_PRELIMITATION_H
#define SORT_PRELIMITATION_H

#define MAXSIZE 10  //用于要排序数组个数最大值

typedef struct {
    int r[MAXSIZE]; //用于存储要排序数组,r[0]可当做临时变量
    int length;     //用于记录顺序表的长度
}SqList;

/**
 * 交换L中数组r的下标为i和j的值
 * @param L
 * @param i
 * @param j
 */
void swap(SqList *L, int i, int j){
    int temp = L->r[i];
    L->r[i] = L->r[j];
    L->r[j] = temp;
}

#endif //SORT_PRELIMITATION_H

冒泡排序

BubbleSort.h

#ifndef SORT_BUBBLESORT_H
#define SORT_BUBBLESORT_H

#define bool int
#define TRUE 1
#define FALSE 0

#include "Prelimitation.h"

/* 对顺序表L做交换排序 */
void BubbleSort0(SqList *L){
    int i, j;
    for(i = 1; i < L->length; i++){
        for(j = i + 1; j <= L->length; j++){
            if(L->r[i] > L->r[j]){
                swap(L, i, j);  //交换L->r[i]与L->r[j]的值
            }
        }
    }
}

void BubbleSort(SqList *L){
    int i, j;
    for(i = 0; i < L->length; i++){
        for(j = L->length; j >= i; j++){    //注意j是从后往前循环
            if(L->r[j] > L->r[j + 1]){      //若牵着大于后者(注意这里与上面算法的差距)
                swap(L, j, j + 1);          //交换L->r[j]与L->r[j + 1]的值
            }
        }
    }
}

//优化
void BubbleSort2(SqList *L){
    int i, j;
    bool flag = TRUE; //flag用来做标记
    for(i = 1; i < L->length && 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);  //交换L->r[j]与L->r[j + 1]的值
                flag = true;        //如果有数据交换,则flag为true
            }
        }
    }
}


#endif //SORT_BUBBLESORT_H

简单选择排序

SelectSort.h

#ifndef SORT_SELECTSORT_H
#define SORT_SELECTSORT_H

#include "Prelimitation.h"

/* 对顺序表L做简单选择排序 */
/**
 * 选择排序
 * @param L
 */
void SelectSort(SqList *L){
    int i, j, min;
    for(i = 1; i < L->length; i++){
        min = i;                                //将当前下表定义为最小值下标
        for(j = i + 1; j <= L->length; j++){    //循环之后的数据
            if(L->r[min] > L->r[j]){            //如果小于当前最小值的关键字
                min = j;                        //将此关键字的下标赋值给min
            }
        }
        if(i != min){       //若min不等于i,说明找到最小值,交换
            swap(L, i, min);//交换L->r[min]与L->r[i]的值
        }
    }
}

#endif //SORT_SELECTSORT_H

直接插入排序

InsertSort.h

#ifndef SORT_INSERTSORT_H
#define SORT_INSERTSORT_H

#include "Prelimitation.h"
/**
 * 插入排序
 * @param L
 */
void InsertSort(SqList *L){
    int i, j;
    for(i = 2; i < L->length; i++){
        if(L->r[i] < L->r[i - 1]){  //需将L->r[i]插入有序子表
            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];  //插入到正确位置
        }
    }
}

#endif //SORT_INSERTSORT_H

希尔排序

ShellSort.h

#ifndef SORT_SHELLSORT_H
#define SORT_SHELLSORT_H

#include "Prelimitation.h"
/**
 * 希尔排序
 * @param L
 */
void ShellSort(SqList *L){
    int i, j;
    int increment = L->length;
    do{
        increment = increment / 3 + 1;  //增量序列
        for(i = increment + 1; i <= L->length; i++){
            if(L->r[i] < L->r[i - increment]){  //需将L->r[i]插入有序增量子表
                L->r[0] = L->r[i];      //暂存在L->r[0]
                for(j = i - increment; j > 0 && L->r[0] > L->r[j]; j -= increment){
                    L->r[j + increment] = L->r[j];//记录后移,查找插入位置
                }
                L->r[j + increment] = L->r[0];  //插入
            }
        }
    }while (increment > 1);
}

#endif //SORT_SHELLSORT_H

堆排序

HeapSort.h

#ifndef SORT_HEAPSORT_H
#define SORT_HEAPSORT_H

#include "Prelimitation.h"
/**
 * 已知L->r[s,m]中记录的关键字除L->r[s]之外均满足堆的定义
 * 本函数调整L-r[s]的关键字,使L->r[s,m]成为一个大顶堆
 * @param L
 * @param s
 * @param m
 */
void HeapAdjust(SqList *L, int s, int m){
    int temp, j;
    temp = L->r[s];
    for(j = 2 * s; j <= m; j *= 2){ //沿关键字较大的孩子节点向下筛选
        if(j < m && L->r[j] < L->r[j + 1]){
            ++j;    //j为关键字中较大的记录的下标
        }
        if(temp >= L->r[j]){
            break;  //rc用插入在位置s上
        }
        L->r[s] = L->r[j];
        s = j;
    }
    L->r[s] = temp; //插入
}
/**
 * 堆排序
 * @param L
 */
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]重新调整为大顶堆
    }
}



#endif //SORT_HEAPSORT_H

归并排序

MergeSort.h

#ifndef SORT_MERGESORT_H
#define SORT_MERGESORT_H

#include 
#include "Prelimitation.h"
/**
 * 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]
 * @param SR
 * @param TR
 * @param i
 * @param m
 * @param n
 */
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] < SR[j]){
            TR[k] = SR[i++];
        } else{
            TR[k] = SR[j++];
        }
    }
    if(i <= m){
        for(l = 0; l <= m - i; l++){//将剩余的SR[i..m]复制到TR
            TR[k + 1] = SR[i + 1];
        }
    }
    if(j <= n){
        for(l = 0; l <= n - j; l++){//将剩余的SR[j..n]复制到TR
            TR[k + l] = SR[j + l];
        }
    }
}
//递归实现
/**
 * 将SR[s..t]归并排序为TR1[s..t]
 * @param SR
 * @param TR1
 * @param s
 * @param t
 */
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]
    }
}

/**
 * 递归归并排序
 * @param L
 */
void MergeSort(SqList *L){
    MSort(L->r, L->r, 1, L->length);
}
//非递归实现
/**
 *
 * @param SR
 * @param TR
 * @param s
 * @param n
 */
void MergePass(int SR[], int TR[], int s, int n){
    int i = 1;
    int j;
    while(i <= n - 2 * s + 1){
        Merge(SR, TR, i, i + s - 1, i + 2 * s - 1); //两两归并
        i = i + 2 * s;
    }
    if(i < n - s + i){  //归并最后两个序列
        Merge(SR, TR, i, i + s - 1, n);
    } else{             //若最后只剩下单个子序列
        for(j = i; j <= n; j++){
            TR[j] = SR[j];
        }
    }
}
/**
 * 非递归归并排序
 * @param L
 */
void MergeSort2(SqList *L){
    int *TR = (int *)malloc(L->length * sizeof(int));   //申请额外空间
    int k = 1;
    while(k < L->length){
        MergePass(L->r, TR, k, L->length);
        k = 2 * k;  //子序列长度加倍
        MergePass(TR, L->r, k, L->length);
        k = 2 * k;  //子序列长度加倍
    }
}

#endif //SORT_MERGESORT_H

快速排序

QuickSort.h

#ifndef SORT_QUICKSORT_H
#define SORT_QUICKSORT_H

#define MAX_LENGTH_INSERT_SORT 7    //数组长度阈值

#include "Prelimitation.h"
#include "InsertSort.h"
/**
 * 交换顺序表L中子表的记录,使枢纽记录到位,并返回其所在位置
 * 此时在他之前(后)的记录均不大(小)于它
 * @param L
 * @param low
 * @param high
 * @return
 */
int Partition(SqList *L, int low, int high){
    int pivotKey;
    pivotKey = L->r[low];   //用子表的第一个记录作为枢纽记录
    while(low < high){      //从标的两端交替向中间扫描
        while(low < high && L->r[high] >= pivotKey){
            high--;
        }
        swap(L, low, high); //将比枢纽记录小得记录交换到低端
        while(low < high && L->r[low] <= pivotKey){
            low++;
        }
        swap(L, low, high); //将比枢纽记录大得记录交换到高端
    }
    return low; //返回枢纽所在位置
}

/**
 * 对顺序表L中的子序列L->r[low..high]做快速排序
 * @param L
 * @param low
 * @param high
 */
void QSort(SqList *L, int low, int high){
    int pivot;
    if(low < high){
        pivot = Partition(L, low, high);    //将L->r[low..high]一分为二
        QSort(L, low, pivot - 1);     //对低子表递归排序
        QSort(L, pivot + 1, high);     //对高子表递归排序
    }
}
/**
 * 快速排序
 * @param L
 */
void QuickSort(SqList *L){
    QSort(L, 1, L->length);
}

//优化
/**
 * 优化不必要的交换
 * @param L
 * @param low
 * @param high
 * @return
 */
int Partition1(SqList *L, int low, int high){
    int pivotKey;
    /**
     * 三数取中法
     * 取三个关键字先进行排序,将中间数作为枢纽,一般是取左端、右端和中间三个数,也可以随机选取
     */
    int m = low + (high - low) / 2;//计算数组中间的元素下标
    if(L->r[low] > L->r[high]){
        swap(L, low, high);     //交换左端与右端数据,保证左端较小
    }
    if(L->r[m] > L->r[high]){
        swap(L, high, m);       //交换中间与右端数据,保证中间较小
    }
    if(L->r[m] > L->r[low]){
        swap(L, m, low);        //交换中间与左端数据,保证左端较小
    }
    //此时L.r[low]已经为整个序列左中右三个关键字的中间值
    pivotKey = L->r[low];       //用子表的第一个做枢纽记录
    L->r[0] = pivotKey;         //将枢纽关键字备份到L->r[0]
    while (low < high){         //从表的两端交替向中间扫描
        while(low < high && L->r[high] >= pivotKey){
            high--;
        }
        L->r[low] = L->r[high]; //采用替换而不是交换的方式进行操作
        while(low < high && L->r[low] <= pivotKey){
            low++;
        }
        L->r[high] = L->r[low]; //采用替换而不是交换的方式进行操作
    }
    L->r[low] = L->r[0];        //将枢纽数值替换回L.r[low]
    return low;                 //返回枢纽所在位置
}
/**
 * 对顺序表L中的子序列L.r[low..high]做快速排序
 * @param L
 * @param low
 * @param high
 */
void QSort(SqList &L, int low, int high){
    int pivot;
    if((high - low) > MAX_LENGTH_INSERT_SORT){//当high-low大于常数时用快速排序
        pivot = Partition(&L, low, high);   //将L.r[low..high]一分为二,并算出枢纽值pivot
        QSort(L, low, pivot - 1);  //对低子表递归排序
        QSort(L, pivot + 1, high);  //对高子表递归排序
    } else{ //当high-low小于等于常数时用直接插入排序
        InsertSort(&L);
    }
}
/**
 * 实施尾递归优化
 * @param L
 * @param low
 * @param high
 */
void QSort1(SqList *L, int low, int high){
    int pivot;
    if((high - low) > MAX_LENGTH_INSERT_SORT){
        while(low < high){
            pivot = Partition(L, low, high);   //将L.r[low..high]一分为二,并算出枢纽值pivot
            QSort(L, low, pivot - 1);  //对低子表递归排序
            low = pivot + 1;    //尾递归
        }
    } else{
        InsertSort(L);
    }
}

#endif //SORT_QUICKSORT_H

拓扑排序

TopologicalSort.h

#ifndef SORT_TOPOLOGICALSORT_H
#define SORT_TOPOLOGICALSORT_H

#include 
#include 
#include "Prelimitation.h"

#define MAXVEX 100

typedef struct EdgeNode{    //边表结点
    int adjVex;     //邻结点域,存储该顶点对应的下标
    int weight;     //用于存储权值,对于非网图可以不需要
    struct EdgeNode *next;  //链域,指向下一个邻结点
}EdgeNode;

typedef struct VertexNode{  //顶点表结点
    int in;     //顶点入度
    int data;   //顶点域,存储定点信息
    EdgeNode *firstEdge;    //边表头指针
}VertexNode, AdjList[MAXVEX];

typedef struct {
    AdjList adjList;
    int numVertexes, numEdges;  //图中当前顶点数和边数
}graphAdjList, *GraphAdjList;

/**
 * 拓扑排序,若GL无回路,则输出拓扑排序序列并返回1,若有活路则返回0
 * @param GL
 * @return
 */
int TopologicalSort(GraphAdjList GL){
    EdgeNode *e;
    int i ,k, getTop;
    int top = 0;    //用于栈指针下标
    int count = 0;  //用于统计输出顶点的个数
    int *stack;     //建栈存储入度为0的顶点
    stack = (int *)malloc(GL->numVertexes * sizeof(int));
    for(i = 0; i < GL->numVertexes; i++){
        if(GL->adjList[i].in = 0){
            stack[++top] = i;   //将入度为0的顶点入栈
        }
    }
    while(top != 0){
        getTop = stack[top--];  //出栈
        printf("%d ->", GL->adjList[getTop].data);  //打印此点
        count++;    //统计输出定点数
        for(e = GL->adjList[getTop].firstEdge; e; e = e->next){ //对此顶点弧表遍历
            k = e->adjVex;
            if(!(--GL->adjList[k].in)){ //将k号顶点邻结点的入度-1
                stack[++top] = k;   //若为0则入栈,以便于下次循环输出
            }
        }
    }
    if(count < GL->numVertexes){    //如果count小于定点数,说明存在环
        return 0;
    } else{
        return 1;
    }
}

#endif //SORT_TOPOLOGICALSORT_H

编译器:Clion
参考书籍:《大话数据结构》

你可能感兴趣的:(C语言,排序算法,算法,算法,c语言,排序算法)