常用排序算法汇总

插入排序

直接插入排序

#include<bits/stdc++.h>
using namespace std;
void InsertSort(int a[], int n) {
    int temp, i, j;
    for(i = 1; i < n; i++) { // 依次将a[1]~a[n-1]插入前面已经排序序列
        if(a[i] < a[i-1]) { //若a[i]关键码小于其前驱,将a[i]插入有序表
            temp = a[i];
            for(j = i - 1;temp < a[j]; j--) a[j + 1] = a[j]; //从后往前查找待插入位置并向后挪位
            a[j+1] = temp;  //复制到插入位置
        }
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n];
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    InsertSort(a, n);
    for(auto &i: a) printf("%d ", i);
    return 0;
}
/*
8
49 38 65 97 76 13 27 49
*/

折半插入排序

#include<bits/stdc++.h>
using namespace std;
void InsertSort(int a[], int n) {
    int i, j, low, high, mid, temp;
    for(i = 1; i < n; i++) {
        temp = a[i];
        low = 0, high = i - 1;
        while(low <= high) { //折半查找
            mid = (low + high) >> 1; // 取中间点
            if(a[mid] > temp) high = mid - 1; //查找左半子表
            else low = mid + 1; //查找右半子表
        }
        for(j = i - 1; j >= high + 1; j--) a[j+1] = a[j]; //统一后移元素,空出插入位置
        a[high+1] = temp; // 插入操作
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n];
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    InsertSort(a, n);
    for(auto &i: a) printf("%d ", i);
    return 0;
}
/*
8
49 38 65 97 76 13 27 49
*/

希尔排序

#include<bits/stdc++.h>
using namespace std;
void ShellSort(int a[], int n) {
    // a[0]只是暂存单元,不是哨兵,当j<=0时,插入位置已满
    int j;
    for(int dk = n / 2; dk >= 1; dk /= 2) { //步长变化
        for(int i = dk + 1; i <= n; i++) {
            if(a[i] < a[i-dk]) { //需将a[i]插入有序增量子表
                a[0] = a[i]; //暂存在a[0]
                for(j = i -dk; j > 0 && a[0] < a[j]; j-= dk) 
                    a[j+dk] = a[j]; //记录后移,查找插入的位置
                a[j+dk] = a[0]; //插入
            }
        }
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n+5];
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    ShellSort(a, n);
    for(int i = 1; i <= n; i++) printf("%d ", a[i]);
    return 0;
}
/*
8
49 38 65 97 76 13 27 49
*/

对链表进行直接插入排序

算法思想:采用直接插入排序算法的思想,先构成只含一个数据结点的有序单链表,然后依次扫描单链表中剩下的结点* p(直到p==NULL为止),在有序表中通过比较查找插入 * p 的前驱结点 * pre,然后将*p插入到 *pre之后。

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    ListNode* insertionSortList(ListNode* head) {
        // write code here
        ListNode *list; // 带头结点的单链表list
        list = (ListNode *) malloc(sizeof(ListNode));
        ListNode *p = head, *r, *pre;
        r = p -> next; // r保持*p后继结点指针,以保证不会断链
        list -> next = p; // 构造只含有一个数据结点的有序表
        p -> next = NULL;
        p = r;
        while(p != NULL) {
            r = p -> next;
            pre = list;
            while(pre -> next != NULL && pre->next->val < p->val)
                pre = pre -> next; // 在有序表中查找插入*p的前驱结点*pre
            p -> next = pre -> next; // 将*p插入到*pre之后
            pre -> next = p;
            p = r; // 扫描原单链表中剩下的结点
        }
        return list -> next;
    }
};

交换排序

冒泡排序

#include<bits/stdc++.h>
using namespace std;
void BubbleSort(int a[], int n) {
    bool flag;
    for(int i = 0; i < n - 1; i++) {
        flag = false; // 表示本趟冒泡是否发生交换的标志
        for(int j = n - 1; j > i; j--) { //一趟冒泡过程
            if(a[j] < a[j - 1]) { // 若为逆序
                swap(a[j], a[j-1]); //交换
                flag = true;
            }
        }
        if(!flag) return; //本趟遍历后没有发生交换,说明表
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n];
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    BubbleSort(a, n);
    for(auto &i: a) printf("%d ", i);
    return 0;
}

快速排序

#include<bits/stdc++.h>
using namespace std;
int Partition(int a[], int low, int high) { //一趟划分
    int piovt = a[low]; //将当前表中第一个元素设为枢轴,对表进行划分
    while(low < high) { //循环跳出条件
        while(low < high && a[high] >= piovt) high--;
        a[low] = a[high]; //将比枢轴小的元素移动到左端
        while(low < high && a[low] <= piovt) low++;
        a[high] = a[low]; // 将比枢轴大的元素移动到右端
    }
    a[low] = piovt; //枢轴元素存放到最终位置
    return low; // 返回存放枢轴的最终位置
}
void QuickSort(int a[], int low, int high) {
    if(low < high) { // 递归跳出的条件
    //Partition()就是划分操作,将表A[low...high]划分为满足上述条件的两个子表
        int piovtpos = Partition(a, low, high); //划分
        QuickSort(a, low, piovtpos - 1); // 依次对两个子表进行递归排序
        QuickSort(a, piovtpos + 1, high);
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n];
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    QuickSort(a, 0, n - 1);
    for(auto &i: a) printf("%d ", i);
    return 0;
}
/*
8
49 38 65 97 76 13 27 49
*/

选择排序

简单选择排序

#include<bits/stdc++.h>
using namespace std;
void SelectSort(int a[], int n) {
    for(int i = 0; i < n - 1; i++) { // 一共进行n-1趟
        int min = i; // 记录最小元素的位置
        for(int j = i + 1; j < n; j++) { //在a[i..n-1]中选择最小元素
            if(a[j] < a[min]) min = j; //更新最小元素的位置
        }
        if(min != i)swap(a[min], a[i]); //swap函数共移动元素三次
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n];
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    SelectSort(a, n);
    for(auto &i: a) printf("%d ", i);
    return 0;
}

堆排序

#include<bits/stdc++.h>
using namespace std;
void HeapAdjust(int a[], int k, int len) {
    // 函数HeapAdjust将元素k为根的子树进行调整
    a[0] = a[k]; //a[0]暂存子树的根节点
    for(int i = 2 * k; i <= len; i *= 2) {
        if(i < len && a[i] < a[i+1]) i++; //取key值较大的子结点的下标
        if(a[0] >= a[i]) break; //筛选结束
        else {
            a[k] = a[i]; //将a[i]调整到双亲结点上
            k = i; //修改k值,以便继续向下筛选
        }
    }
    a[k] = a[0]; //被筛选结点的值放入最终位置
}
void BuildMaxHeap(int a[], int len) {
    for(int i = len / 2; i > 0; i--) //从i=[n/2] ~ 1反复调整堆
        HeapAdjust(a, i, len); 
}
void HeapSort(int a[], int len) {
    BuildMaxHeap(a, len); //初始建堆
    for(int i = len; i > 1; i--) { //n-1趟的交换和建堆过程
        swap(a[i], a[1]); //输出堆顶元素(和堆底元素交换)
        HeapAdjust(a, 1, i - 1);
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n + 10];
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    HeapSort(a, n);
    for(int i = 1; i <= n; i++) printf("%d ", a[i]);
    return 0;
}
/*
7
32 17 45 78 65 53 9
*/

对链表进行简单选择排序

算法思想:每趟在原始链表中摘下关键字最大的结点,把它插入结果链表的最前端,由于在原始链表中摘下的关键字越来越小,在结果链表前端插入的关键字也越来越小,因此最后形成的结果链表中的结点将按关键字非递减的顺序有序链接。
假设单链表不带头结点

/**
 * Definition for singly-linked list.
 * typedef struct ListNode {
 *     int val;
 *     ListNode *next;
 * }ListNode, *LinkList;
 */
    void SelectSortList(LinkList &L) {
        // 对不带头结点的单链表L执行简单选择排序
        ListNode *h = L, *p, *q, *r, *s;
        L = NULL;
        while(h != NULL) {
            p = s = h, q = r = NULL;
            //指针 s 和 r 记忆最大结点和其前驱,p 为工作指针,q 为其前驱
            while(p != NULL) { // 扫描原链表寻找最大结点 s
                if(p->val > s->val) { // 找到更大的,记忆它和它的前驱
                    s = p, r = q;
                }
                q = p, p = p -> next; //继续寻找
            }
            if(s == h) h = h -> next; // 最大结点在原链表最前端
            else r -> next = s -> next; // 最大结点在原链表表内
            s -> next = L; //结点 s 插入结果链表前端
            L = s;
        }
    }

归并排序

递归实现

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+1;
int *b = (int *)malloc(maxn*sizeof(int)); //辅助数组b
void Merge(int a[], int low, int mid, int high) {
    //表a的两段a[low...mid]和a[mid+1...high]各自有序,将它们合并成一个有序表
    for(int k = low; k <= high; k++)
        b[k] = a[k]; // 将a中所有的元素复制到b中
    int i, j, k;
    for(i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
        if(b[i] <= b[j]) a[k] = b[i++]; //比较b的左右两段中的元素,将较小值复制到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 low, int high) {
    if(low < high) {
        int mid = (low + high) / 2; //从中间划分两个子序列
        MergeSort(a, low, mid); //对左侧子序列进行递归排序
        MergeSort(a, mid+1, high); //对右侧子序列进行递归排序
        Merge(a, low, mid, high); //归并
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n + 10];
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    MergeSort(a, 1, n);
    for(int i = 1; i <= n; i++) printf("%d ", a[i]);
    return 0;
}
/*
7
32 17 45 78 65 53 9
*/

非递归实现

//归并排序非递归算法
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+1;
int *b = (int *)malloc(maxn*sizeof(int)); //辅助数组b
void Merge(int a[], int low, int mid, int high) {
    //表a的两段a[low...mid]和a[mid+1...high]各自有序,将它们合并成一个有序表
    for(int k = low; k <= high; k++)
        b[k] = a[k]; // 将a中所有的元素复制到b中
    int i, j, k;
    for(i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
        if(b[i] <= b[j]) a[k] = b[i++]; //比较b的左右两段中的元素,将较小值复制到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) {
    //step为组内元素个数,step / 2为左子区间元素个数
    for(int step = 2; step / 2 <= n; step *= 2) {
        //每step个元素一组,组内[i, min(i+step, n+1)] 进行排序
        for(int i = 1; i <= n; i += step) {
            int mid = i + step / 2 - 1; //左子区间元素个数为step / 2
            if(mid + 1 <= n) { //右子区间存在元素则合并
                //左子区间为[i, mid],右子区间为[mid+1, min(i+step-1, n)]
                Merge(a, i, mid, min(i + step - 1, n));
            }
        }
    }
}
int main() {
    int n;
    scanf("%d", &n);
    int a[n + 10];
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    MergeSort(a, n);
    for(int i = 1; i <= n; i++) printf("%d ", a[i]);
    return 0;
}
/*
7
32 17 45 78 65 53 9
*/

合并两个有序单链表

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        ListNode *pHead3, *s;
        if(pHead1 == NULL && pHead2 == NULL) return NULL;
        else if(pHead1 == NULL) return pHead2;
        else if(pHead2 == NULL) return pHead1;
        if(pHead1 -> val < pHead2 -> val) {
            pHead3 = s = pHead1;
            pHead1 = pHead1 -> next;
        }
        else {
            pHead3 = s = pHead2;
            pHead2 = pHead2 -> next;
        }
        while(pHead1 != NULL && pHead2 != NULL) {
                if(pHead1->val < pHead2->val) {
                    s -> next = pHead1;
                    s = pHead1;
                    pHead1 = pHead1 -> next;
                } else {
                    s -> next = pHead2;
                    s = pHead2;
                    pHead2 = pHead2 -> next;
                }
        }
        if(pHead1 == NULL) s -> next = pHead2;
        if(pHead2 == NULL) s -> next = pHead1;
        return pHead3;
    }
};

各排序算法性质

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值