数据结构-6

第十一章 排序

1.为什么要学排序

2 常见排序算法以及实现

插入排序

cpp 复制代码
插⼊排序(Insertion Sort)类似于玩扑克牌插牌过程,每次将⼀个待排序的元素按照其关键字⼤⼩插⼊
到前⾯已排好序的序列中,按照该种⽅式将所有元素全部插⼊完成即可。

把大的数字后移

cpp 复制代码
#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int n;
int a[N];

// 直接插入排序(数组下标从1开始)
void insert_sort()
{
    // a[1]默认有序,从第2个元素开始处理
    for (int i = 2; i <= n; i++)
    {
        int key = a[i];
        int j = i - 1;
        // 往前遍历,比key大的元素全部向后挪一位
        while (j >= 1 && a[j] > key)
        {
            a[j + 1] = a[j];
            j--;
        }
        // 空位放入当前待插入元素key
        a[j + 1] = key;
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    insert_sort();
    for (int i = 1; i <= n; i++)
    {
        cout << a[i] << " ";
    }
    return 0;
}

升序的时候只需要扫描一遍就可以了

选择排序

cpp 复制代码
选择排序(Selection Sort)是⼀种特别直观的排序算法。每次找出未排序序列中最⼩的元素,然后放进
有序序列的后⾯。
cpp 复制代码
#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int n;
int a[N];

// 选择排序(数组下标从1开始,升序排列)
void selection_sort()
{
    // i代表已排序区间末尾的下一个位置,一共需要确定 n-1 个元素
    for(int i = 1; i < n; i++)
    {
        int pos = i; // 记录最小值下标,初始假定当前i位置最小
        // 在 [i, n] 未排序区间里寻找最小值下标
        for(int j = i + 1; j <= n; j++)
        {
            if(a[j] < a[pos])
            {
                pos = j;
            }
        }
        // 将找到的最小值交换到当前i的位置
        swap(a[i], a[pos]);
    }
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    selection_sort();
    for(int i = 1; i <= n; i++)
    {
        cout << a[i] << " ";
    }
    return 0;
}

冒泡排序

两两比较 不断比较

这个是没有优化的

而优化的是当在for循环的时候不进行交换 那么就交换完成了

cpp 复制代码
#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int n;
int a[N];

// 带有序标记优化版冒泡排序(升序,数组下标从1开始)
void bubble_sort()
{
    // i:每轮冒泡后,末尾i位置已有序,无序区间为 [1, i]
    for (int i = n; i > 1; i--)
    {
        bool flag = false; // 标记本轮是否发生交换
        // 相邻元素两两比较,大值向后冒泡
        for (int j = 1; j < i; j++)
        {
            if (a[j] > a[j + 1])
            {
                swap(a[j], a[j + 1]);
                flag = true;
            }
        }
        // 本轮没有任何交换,说明数组整体已经有序,直接提前退出
        if (flag == false)
            return;
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    bubble_sort();
    for (int i = 1; i <= n; i++)
    {
        cout << a[i] << " ";
    }
    return 0;
}

堆排序

重新创建一个堆 然后将数据传进去 这个堆是不传统的

传统的是在原有得到数据上进行操作堆

cpp 复制代码
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N];

// 堆下沉操作:维护以parent为根,长度为len的大根堆
void down(int parent, int len)
{
    int child = parent * 2;
    while(child <= len)
    {
        // 选出左右子节点中更大的那个
        if(child + 1 <= len && a[child + 1] > a[child]) 
            child++;
        // 父节点大于等于最大子节点,无需下沉直接退出
        if(a[parent] >= a[child]) 
            return;
        // 父子交换
        swap(a[parent], a[child]);
        // 更新父、子节点下标,继续向下调整
        parent = child;
        child = parent * 2;
    }
}

void heap_sort()
{
    // 1. 自底向上建大根堆
    for(int i = n / 2; i >= 1; i--)
    {
        down(i, n);
    }
    // 2. 堆顶最大值交换到数组末尾,再调整剩余堆
    for(int i = n; i > 1; i--)
    {
        swap(a[1], a[i]);
        down(1, i - 1);
    }
}

int main()
{
    cin >> n;
    // 数组从下标1开始存储数据
    for(int i = 1; i <= n; i++) 
        cin >> a[i];
    heap_sort();
    // 输出排序后的数组
    for(int i = 1; i <= n; i++) 
        cout << a[i] << " ";
    return 0;
}

快速排序

cpp 复制代码
#include <iostream>
#include <ctime>
using namespace std;

int main()
{
    srand(time(0)); // 种下一个随机数种子
    for (int i = 1; i <= 10; i++)
    {
        cout << rand() << endl; // 每次生成一个随机值
    }
    return 0;
}
cpp 复制代码
#include <iostream>
#include <ctime>
#include <algorithm> // swap函数头文件,补上更规范
using namespace std;

const int N = 1e5 + 10;
int n;
int a[N];

// 随机选取 [left, right] 范围内的基准值
int get_random(int left, int right)
{
    int pos = rand() % (right - left + 1) + left;
    return a[pos];
}

// 荷兰国旗快排:小于p | 等于p | 大于p 三段划分
void quick_sort(int left, int right)
{
    if (left >= right)
        return;

    int p = get_random(left, right);
    int l = left - 1;
    int i = left;
    int r = right + 1;

    while (i < r)
    {
        if (a[i] < p)
        {
            swap(a[++l], a[i++]);
        }
        else if (a[i] == p)
        {
            i++;
        }
        else // a[i] > p
        {
            swap(a[--r], a[i]);
        }
    }
    // [left, l] 小于基准,[l+1, r-1]等于基准,[r, right]大于基准
    quick_sort(left, l);
    quick_sort(r, right);
}

int main()
{
    srand(time(0)); // 设置随机种子
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    quick_sort(1, n);

    for (int i = 1; i <= n; i++)
        cout << a[i] << " ";
    return 0;
}

归并排序

cpp 复制代码
#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int n;
int a[N];
int tmp[N]; // 归并合并阶段使用的临时辅助数组

void merge_sort(int left, int right)
{
    // 区间只有一个元素,天然有序,直接返回
    if (left >= right)
        return;

    // 中点拆分区间
    int mid = (left + right) >> 1; // 等价于 (left + right) / 2

    // 递归分别排序左半段、右半段
    merge_sort(left, mid);
    merge_sort(mid + 1, right);

    // 合并两个已经有序的子数组
    int cur1 = left;    // 左区间遍历指针
    int cur2 = mid + 1; // 右区间遍历指针
    int i = left;       // tmp数组写入指针

    // 双指针合并,取较小值放入tmp
    while (cur1 <= mid && cur2 <= right)
    {
        if (a[cur1] <= a[cur2])
            tmp[i++] = a[cur1++];
        else
            tmp[i++] = a[cur2++];
    }
    // 左区间剩余元素全部拷贝
    while (cur1 <= mid)
        tmp[i++] = a[cur1++];
    // 右区间剩余元素全部拷贝
    while (cur2 <= right)
        tmp[i++] = a[cur2++];

    // 把临时数组有序数据写回原数组a
    for (int j = left; j <= right; j++)
        a[j] = tmp[j];
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    merge_sort(1, n);

    for (int i = 1; i <= n; i++)
        cout << a[i] << " ";

    return 0;
}
相关推荐
Rabitebla2 小时前
C++ STL 之 set 详解:从底层红黑树到实际应用
开发语言·数据结构·c++·算法·leetcode
520拼好饭被践踏2 小时前
JAVA+Agent学习day26
java·开发语言·数据结构·学习·agent
郝学胜-神的一滴2 小时前
力扣 692:巧用小顶堆高效求解前K个高频单词
java·数据结构·python·程序人生·算法·leetcode·职场和发展
额,不知道写啥。3 小时前
题解:P16710 愿望
数据结构·算法
bnmoel3 小时前
数据结构深度剖析二叉树・下篇:链式结构的实现 ,遍历方法全解析
c语言·数据结构·算法·二叉树·
码哥DFS4 小时前
算法练习day1-备战2027届秋招
前端·javascript·数据结构·算法
wabs6664 小时前
关于图论【卡码网108.多余的边的思考】
数据结构·算法·图论
三克的油4 小时前
数据结构-5
数据结构
冻柠檬飞冰走茶4 小时前
PTA基础编程题目集 7-37 整数分解为若干项之和(C语言实现)
c语言·开发语言·数据结构·算法