【插入排序】直接插入排序、折半插入排序、希尔排序

直接插入排序

核心就是遍历数组,从后向前插入到先前一个已经有序的子序列中。每次都遵循“边比较边插入”,是一个\(O(n^2)\)的算法

点击查看代码
#include<iostream>
#include<vector>
using namespace std;


void InsertSort(vector<int> &grid) {
    int size = grid.size() - 1;
    if (size <= 1) return;
    for (int i = 2; i <= size; i++) {
        grid[0] = grid[i];
        int j;
        for (j = i - 1; grid[0] < grid[j]; j--) {
            grid[j + 1] = grid[j];
        }
        grid[j + 1] = grid[0];
    }
}


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

    InsertSort(a);
    for (int i = 1; i <= m; i++) {
        cout << a[i] << endl;
    }

}

折半插入排序

是直接插入排序的改进,改进的点就是将“边比较边插入”改成了先找到插入点,之后一次性插入。而对于找到插入点,用的就是折半查找。下面的用的是左闭右闭,使用左闭右开的可自行更改。同样,折半插入也是一个\(O(n^2)\)的算法

折半插入改进之后使得排序的比较次数改变,取决于表中元素个数n,而移动次数不变,仍然取决于初始状态。

点击查看代码
#include<iostream>
#include<vector>
using namespace std;

void InsertSort(vector<int> &grid) {
    int size = grid.size() - 1;
    if (size <= 1) return;
    for (int i = 2; i <= size; i++) {
        grid[0] = grid[i];
        int left = 1; 
        int right = i - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (grid[mid] > grid[0]) {// tar位于左区间,mid是左区间的右边界,更新右边界
                right = mid - 1;
            } else if (grid[mid] < grid[0]) { // tar位于右区间,mid为右区间的左边界,更新左边界
                left = mid + 1;
            }
        }
        for (int j = i - 1; j >= left; j--) {
            grid[j + 1] = grid[j];
        }
        grid[left] = grid[0];
    }
}

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

    InsertSort(a);
    for (int i = 1; i <= m; i++) {
        cout << a[i] << endl;
    }
    
}

希尔排序

希尔排序的就是在前面的部分引入了一个增量的概念,剩下的部分都就是将直接插入排序中递增1改为递增一个增量。所以,因为增量的引入,在dk比较大的时候,就像是在两两交换,但是在dk较小能将整个数组间隔开多个的时候,这些间隔开的数之间就是直接插入排序。

因为希尔排序这种多间隔的增量方式,使得希尔排序是一个不稳定的算法

点击查看代码
#include<iostream>
#include<vector>
using namespace std;


void ShellSort(vector<int> &grid) {
    int size = grid.size() - 1;
    if (size <= 1) return;
    int dk, i, j;
    for (dk = size/2; dk >= 1; dk/=2) { 
        for (i = dk + 1; i <= size; i++) {
            if (grid[i] < grid[i - dk]) { // 如果grid[i] < grid[i - dk]才要进行排序,下面开始寻找插入位置
                // 此时前面的部分相当于一个部分有序序列
                grid[0] = grid[i];
                for (j = i - dk; j > 0 && grid[0] < grid[j]; j-=dk) { //每次的增量是dk
                    grid[j + dk] = grid[j];
                }
                grid[j + dk] = grid[0];
            }
        }
    }
}


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

    ShellSort(a);
    for (int i = 1; i <= m; i++) {
        cout << a[i] << endl;
    }

}
posted on 2025-06-25 15:55  bnbncch  阅读(6)  评论(0)    收藏  举报