数据结构 排序

image

插入排序

直接插入排序

基本思想:
每步将一个待排序的元素,插入到已经排好序的一组元素的适当位置上去,直到元素全部插入为止。
基本操作:

  1. 将待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤2~5。
    图示:
    image

代码


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define PII pair<int, int>
#define x first
#define y second
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const ll M = 1e9 + 7;
const int N = 10010;
int a[maxn];

void insert(int n)
{
    int k = a[n];
    int i = n;
    while (a[i - 1] > k)
    {
        a[i] = a[i - 1];
        i--;
        if (i == 0) break;
    }
    a[i] = k;
}
void insertionSort(int n)
{
    int i;
    for (int i = 1; i < n; i++)
    {
        insert(i);
    }
}
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    //排序
    insertionSort(n);

    //输出
    for (int i = 0; i < n; i++)
    {
        if (i == n - 1)
            cout << a[i] << endl;
        else
            cout << a[i] << " ";
    }

    return 0;
}

插入排序转自

希尔排序

思想:
对于n个元素的待排序的数列,

  • 取一个小于n的整数gap(gap被称为步长)将待排序元素分成若干个组子序列,所有距离为gap的倍数的记录放在同一个组中;
  • 然后,对各组内的元素进行直接插入排序。 这一趟排序完成之后,每一个组的元素都是有序的。
  • 然后减小gap的值,并重复执行上述的分组和排序。重复这样的操作,当gap=1时,整个数列就是有序的。
    图示
    image

特点:

  • 一次移动移动位置大,跳远的接近排序后的最终位置。
  • 增量序列必须递减,最后一个必须是1
  • 增量序列应该是互质的
    希尔排序是不稳定排序
    image

希尔排序的时间复杂度
与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量的希尔排序的时间复杂度为O(N3/2)。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define PII pair<int, int>
#define x first
#define y second
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const ll M = 1e9 + 7;
const int N = 10010;
int a[maxn];
int n;
void xisort(int x)
{
    for (int i = x; i < n; i++)
    {
        for (int j = i - x; j >= 0; j -= x)
        {
            if (a[j] > a[j + x])
            {
                swap(a[j], a[j + x]);
            }
        }
    }
}
int main()
{
    while (cin >> n)
    {
        for (int i = 0; i < n; i++)
        {
            cin >> a[i];
        }
        int dk = n / 2;
        xisort(dk);
        for (int i = 0; i < n; i++)
        {
            if (i == n - 1)
                cout << a[i] << endl;
            else
                cout << a[i] << " ";
        }

        dk = 1;
        xisort(dk);
        for (int i = 0; i < n; i++)
        {
            if (i == n - 1)
                cout << a[i] << endl;
            else
                cout << a[i] << " ";
        }
    }
    return 0;
}

交换排序

冒泡排序

思想

基本思想

  • 将序列当中的左右元素,依次比较,保证右边的元素始终大于左边的元素;
    ( 第一轮结束后,序列最后一个元素一定是当前序列的最大值;)
  • 对序列当中剩下的n-1个元素再次执行步骤1。
  • 重复多次,直到有序。

image

时间复杂度
On2
辅助空间:
O1
稳定性
稳定的

代码

代码1:常用

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define PII pair<int, int>
#define x first
#define y second
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const ll M = 1e9 + 7;
const int N = 10010;
int a[maxn];

int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    //排序
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = 0; j < n - 1 - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                swap(a[j], a[j + 1]);
            }
        }
    }

    //输出
    for (int i = 0; i < n; i++)
    {
        if (i == n - 1)
            cout << a[i] << endl;
        else
            cout << a[i] << " ";
    }

    return 0;
}

代码2:抽出函数体

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define PII pair<int, int>
#define x first
#define y second
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const ll M = 1e9 + 7;
const int N = 10010;
int a[maxn];

//一次冒泡
void bubble(int n){
    for(int i=0;i<n-1;i++){
        if(a[i]>a[i+1]){
            swap(a[i],a[i+1]);
        }
    }
}
void bubbleSort(int n){
    for(int i=n;i>=1;i--){
        bubble(i);
    }
}
int main()
{
    int n;
      cin>>n;
        for (int i = 0; i < n; i++)
        {
            cin >> a[i];
        }
        bubbleSort(n);
//输出
        for (int i = 0; i < n; i++)
        {
            if (i == n - 1)
                cout << a[i] << endl;
            else
                cout << a[i] << " ";
        }
    
    return 0;
}

快速排序

基本思想:

  • 从序列当中选择一个基准数(pivot)
    一般选择序列当中第一个数为基准数
  • 将序列当中的所有数依次遍历,比基准数大的位于其右侧,比基准数小的位于其左侧,形成两个子表。
  • 对子表重复步骤1.2,直到所有子集当中只有一个元素为止。

image
时间复杂度
平均时间最快。
越乱速度越快,基本有序的情况下On2。
快速排序不是原地排序
需要O logn的栈空间。
最快是O n
快速排序不是稳定排序

选择排序

简单选择排序

基本思想:
在待排序的数据中选出最大(小)的元素放在其最终的位置。
基本操作:

  1. 首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将 它与第一个记录交换
  2. 再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换
  3. 重复上述操作,共进行n-1趟排序后,排序结束
    图示:
    image

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define PII pair<int, int>
#define x first
#define y second
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const ll M = 1e9 + 7;
const int N = 10010;
int a[maxn];
int findMaxPos(int n)
{
    int maxNumber = a[0];
    int maxid = 0;
    for (int i = 0; i < n; i++)
    {
        if (a[i] > maxNumber)
        {
            maxNumber = a[i];
            maxid = i;
        }
    }
    return maxid;
}
void selectionSort(int n)
{
    while (n > 1)
    {
        int maxid = findMaxPos(n);
        swap(a[maxid], a[n - 1]);
        n--;
    }
}
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    //排序
    selectionSort(n);

    //输出
    for (int i = 0; i < n; i++)
    {
        if (i == n - 1)
            cout << a[i] << endl;
        else
            cout << a[i] << " ";
    }

    return 0;
}

posted @ 2021-12-30 08:48  kingwzun  阅读(36)  评论(0编辑  收藏  举报