【速查】排序算法

排序算法速查


1.插入排序

(1)直接插入排序
//直接插入排序 不带哨兵
void insertSort(SqList &L) {
    int i, j;
    for (i = 0; i < L.length; ++i) {
        if (L.elem[i] < L.elem[i - 1]) {
            int x = L.elem[i];
            for (j = i - 1; L.elem[j] > x && j >= 0; --j)//顺序查找找到插入的位置
                L.elem[j + 1] = L.elem[j];//所有大于x的记录都将后移
            L.elem[j + 1] = x;//插入元素
        }
    }
}
(2)折半插入排序
//折半插入排序 不带哨兵
void BInsertSort1(SqList &L) {
    for (int i = 0; i < L.length; ++i) {
        int x = L.elem[i];//插入排序目标值
        //利用二分查找寻找插入位置 high + 1为插入位置
        int low = 0;
        int high = i - 1;
        while (low <= high) {
            int mid = (low + high)/2;
            if (x < L.elem[mid]) high = mid - 1;
            else low = mid + 1;
        }
        //查找位置结束后 进行常规插入操作
        for (int j = i - 1; j >= high + 1; --j) L.elem[j + 1] = L.elem[j];//j+1插入位置后的元素后移
        L.elem[high + 1] = x;//插入元素
    }
}
/*
直到low > high时才停止折半查找
当mid所指元素等于当元素时 应继续令low = mid + 1以保证稳定性
最终应将当前元素插入到low所指的位置(high + 1)
*/
(3)希尔排序
//间隔内直接插入排序
void shellInsert(SqList &L, int dk) {
    //对顺序表L进行一趟增量为dk的shell排序,其中dk为步长因子
    for (int i = dk + 1; i <= L.length; ++i) {
        if (r[i].key < r[i - dk].key) {
            r[0] = r[i];
            for (int j = i - dk; j > 0 && (r[0].key < r[j].key); j = j - dk) r[j + dk] = r[j];
            r[j + dk] = r[0];
        }
    }
}
void shellSort(SqList &L, int dlta[], int t) {
    //dk值依次存在dlta[t]中
    //按增量序列dlta[0..t-1]对顺序表L作希尔排序
    for (int k = 0; k < t; ++k) {
        shellInsert(L, dlta[k]);//一趟增量为dlta[k]的插入排序
    }
}
(4)表插入排序
//表插入排序
void tableInsertSort(Table &tb, int n) {
    //1.将静态链表中数组下标为1的结点和表头结点构成一个循环链表
    tb[0].next = 1;
    //2.依次将下标为 2~n 的结点按照 关键字非递减 有序插入到循环链表中
    int p, q;//q为p的前驱
    for (int i = 2; i < n; ++i) {
        //调整p、q位置
        q = 0;
        p = tb[0].next;
        while (p != 0 && tb[p].data <= tb[i].data) {
            q = p;
            p = tb[p].next;
        }
        //进行插入操作
        tb[i].next = tb[q].next;
        tb[q].next = i;
    }
}
//对表插入排序后的记录进行重排序
//根据静态链表tb中各结点的指针值调整记录位置 使得tb中记录 按关键字非递减
void Arrange(Table &tb,int n) {
    int p, q;
    p = tb[0].next;
    for (int i = 1; i < n; ++i) {
        //1.调整p、q位置
        while (p < i) p = tb[p].next;//找到第i个记录 并用p指示其在tb中当前的位置
        q = tb[p].next;//q指示尚未调整的表尾
        //2.进行调整
        if (p != i) {
            swap(tb[p], tb[i]);//交换整个记录(包括 data和 next) 使第i个记录到位
            tb[i].next = p;//tb[i].next指向被移动的记录 使得后续可由 while循环找回
        }
        //3.p指向尚未调整的表尾 为找第i + 1个记录作准备
        p = q;
    }
}

2.交换排序

(1)冒泡排序
//i范围为(0 ~ n-2) j范围为(0 ~ n-i-2)
void bubbleSort(SqList &L) {
    int n = L.length;
    for (int i = 0; i < n - 1; ++i) {//需要n - 1趟
        for (int j = 0; j < n - i - 1; ++j) {
            if (L.elem[j] > L.elem[j + 1]) 
                swap(L.elem[j], L.elem[j + 1]);//发生逆序则进行交换
        }
    }
}
//改进的冒泡排序算法:若发现某次遍历后已经是有序的序列,则可直接跳出循环无需再遍历
//新增flag用于标记是否发生交换
void bubbleSort(SqList &L) {
    int flag = 1;
    int n = L.length;
    for (int i = 1; i < n && flag; ++i) {//需要n - 1趟
        flag = 0;
        for (int j = 0; j < n - i; ++j) {
            if (L.elem[j] > L.elem[j + 1]) {
                flag = 1;
                swap(L.elem[j], L.elem[j + 1]);//发生逆序则进行交换
            }
        }
    }
}
(2)快速排序
//选出pivot并对SqList进行排序
int partition(SqList &L, int low, int high) {
    int key = L.elem[low];//取low处元素的值作为比较参考
    while(low < high) {
        while(low < high && L.elem[high] >= key) --high;//右侧比temp元素大的元素结点不动
        L.elem[low] = L.elem[high];//将比key元素小的结点搬到low位置
        while(low < high && L.elem[low] <= key) ++low;//左侧比temp元素小的元素结点不动
        L.elem[high] = L.elem[low];//将比key元素大的结点搬到high位置
    }
    L.elem[low] = key;//low = high = pivot
    return low;
}

void QSort(SqList &L, int low, int high) {//快速排序调用并指明排序下标范围(low ~ high)
    if (low < high) {//排序区间长度大于1则继续递归,否则退出递归
        int pivot = partition(L, low, high);//选出pivot并对SqList进行排序
        QSort(L, low, pivot - 1);
        QSort(L, pivot + 1, high);
    }
}

3.选择排序

(1)选择排序
void selectSort(SqList &L) {
    for (int i = 0; i < L.length - 1; ++i) {
        //从待排序序列中选出最小值
        int min = i;
        for (int j = i + 1; j < L.length; ++j) {
            if (L.elem[j] < L.elem[min]) min = j;//更新最小值位置
        }
        //如果最小值为自己则不进行元素交换
        if (min != i) {
            int temp = L.elem[i];
            L.elem[i] = L.elem[min];
            L.elem[min] = temp;
        }
    }
}
(2)堆排序
//将以x为根的子树调整为大根堆
void HeapAdjust(int R[], int x, int n) {
    int rc = R[x];
    for (int i = 2*x; i <= n; i *= 2) {//沿较大的孩子结点向下筛选(2*x即为较大孩子)
        if (i < n && R[i] < R[i + 1]) i = i + 1;//对比左右孩子的大小 取key为较大的孩子节点的下标(保证有右孩子)
        if (rc >= R[i]) break;//若rc已经满足大根堆的要求 则筛选直接结束
        eles {
            R[x] = R[i];//将A[i]调整到双亲结点上
            x = i;//修改x值为i继续向下筛选(实现树的继续向下筛选)
        }
    }
    R[x] = rc;//被筛选结点的值放入最终位置
}
//堆排序下标范围为  0 - length-1
void HeapSort(int R[], int n) {//对R[1]到R[n]进行堆排序
    //1.建立初始堆O(n)
    for (int i = (n-1)/2; i >= 0; --i) HeapAdjust(R, i, n);
    //2.堆去顶后重构O(nlogn)
    for (int i = n - 1; i > 0; --i) {//去顶重构n-1次
        swap(R[0], R[i]);//根与最后一个元素交换(去顶)
        HeapAdjust(R, 0, i - 1);//重新建堆
    }
}
//堆排序下标范围为 1 - length
void HeapSort(int R[], int n) {//对R[1]到R[n]进行堆排序
    //1.建立初始堆O(n)
    for (int i = n/2; i >= 1; --i) HeapAdjust(R, i, n);
    //2.堆去顶后重构O(nlogn)
    for (int i = n; i > 1; --i) {//去顶重构n-1次
        swap(R[1], R[i]);//根与最后一个元素交换(去顶)
        HeapAdjust(R, 1, i - 1);//重新建堆
    }
}

4.归并排序

//[low...mid]和A[mid+1...high]各自有序 将两个部分归并
void merge(int A[], int n, int low, int mid, int high) {
    int i, j, k;
    int *B = (int *)malloc(n*sizeof(int));//辅助数组B
    for (k = low; k <= high; ++k) B[k] = A[k];//将A中的所有元素复制到B中
    for (i = low, j = mid + 1, k = i; i <= mid && j <= high; ++k) {//归并操作
        if (B[i] <= B[j]) A[k] = B[i++];//将较小值复制到A中
        else A[k] = B[j++];
    }
    while(i <= mid) A[k++] = B[i++];//未归并完的部分直接复制到尾部
    while(j <= high) A[k++] = B[j++];
}

void mergeSort(int A[], int n, int low, int high) {
    if (low < high) {
        int mid = (low + high)/2;//从中间划分
        mergeSort(A, n, low, mid);//左半部分归并排序
        mergeSort(A, n, mid + 1, high);//右半部分归并排序
        merge(A, n, low, mid, high);//归并操作
    }
}
mergeSort(L.elem, L.length, 0, L.length - 1);

详细使用介绍参见:https://blog.csdn.net/weixin_49167174/article/details/125179719

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值