排序:基本概念

1.基于插入:
(1)直接插入排序
(2)希尔(shell)排序算法
2.基于交换:
(1)冒泡排序
(2)快速排序
3.基于选择:
(1)简单选择排序 
(2)堆排序
4.其他:
(1)归并排序
(2)基于计数的排序

如何判断排序好坏:

1.就地排序/非就地排序(反映空间复杂度)
(1)如果在排序过程中,只使用到了存储数据的空间,没有使用其他额外空间,称为是就地排序
2.内部排序/外部排序
(1)待排序数据能够一次性放到内存中---->内部排序
(2)待排序数据不能够一次性放到内存中---->外部排序
注:目前只有归并排序是外部排序
3.稳定排序/不稳定排序
(1)排序前后相同数据的相对位置没有发生变化---->稳定的
(2)排序前后相同数据的相对位置发生变化---->不稳定的
4.时间复杂度


(1)直接插入排序:在添加新的数据时,我们使用顺序查找(遍历)的方式,找到其要插入的位置,将其插入
//(将数据分为有序区与待排序区,基本所有排序算法都会将数据分为这两个区域)
时间复杂度:O(n^2)
注:第一版代码不稳定,略加优化后稳定,时间复杂度不变
是否稳定:稳定
为就地排序
    -折半插入排序 //优化:将直接插入排序中顺序查找换成二分查找,时间复杂度不变,为稳定排序
    -2路插入排序 //优化:在折半插入排序基础上,引入一个循环数组,将排序过程中移动次数减少,时间复杂度不变,为非就地排序


注:在使用直接插入排序时,如果表中记录只有个别是无序的,多数保持有序,这种情况下算法的效率也会比较高,此外,如果需要排序数据总量较少,算法效率同样会很高。下述希尔排序便是基于这两点进行改进。

(2)希尔(shell)排序算法(缩小增量排序算法):在直接插入排序算法的基础上,对待排序数据进行分组,先对每组进行排序,然后不断缩小组数,不断排序,最终缩小为一组。

分组:分成组数与数据下标增量相同,如0--3四个数据,分为0 2,1 3

增量的选择:对n个数据进行排序,依次分为 n/2,n/4,n/8...1组 ---->希尔增量序列

时间复杂度:最坏为O(n^2)
是否稳定:不稳定
为就地排序
//上述为取希尔增量序列时的情况

注:直接插入排序就是增量为一的希尔排序


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
using namespace std;
//直接插入排序(不稳定)
void Insert_Sort(vector<int>(&v))
{
    //保存待排序数据
    int tmp(0);
    //保存待排序数据应该所处位置下标
    int ind(0);

    //第一趟可以不排
    for (int i = 1; i < v.size(); ++i)
    {
        //第二趟开始排序
        tmp = v[i];
        ind = i;
        //有序区0 ---> i - 1
        for (int j = 0; j < i; ++j)
        {
            if (v[j] > tmp)
            {
                //找第一个大于tmp的数
                ind = j;
                break;
            }
        }
        //ind到i - 1下标对应数据全部后移
        for (int j = i; j > ind; --j)
        {
            v[j] = v[j - 1];
        }
        v[ind] = tmp;
    }
}
//略加优化,变为稳定版本
void Insert_Sort_2(vector<int>(&v))
{
    //保存待排序数据
    int tmp(0);
    
    //第一趟可以不排
    for (int i = 1; i < v.size(); ++i)
    {
        //第二趟开始排序
        tmp = v[i];
        //有序区0 ---> i - 1
        //保存待排序数据应该所处位置下标
        int j(0);
        //从i-1位置往回比较
        for (j = i; j > 0; --j)
        {
            if (tmp < v[j - 1])
            {
                v[j] = v[j - 1];
            }
            else
            {
                break;
            }
        }
        v[j] = tmp;
    }
}
void Shell_Sort(vector<int>(&v))
{
    //保存待排序数据
    int tmp(0);
    int k(0);//趟数
    //枚举增量/组数
    for (int d = v.size() / 2; d >= 1; d /= 2)
    {
        k++;//记录趟数
        //从每一组第二个数开始排序
        for (int i = d; i < v.size(); ++i)
        {
            tmp = v[i];
            //保存待排序数据应该所处位置下标
            int j(0);
            for (j = i - d; j >= 0; j -= d)
            {
                if (tmp < v[j])
                {
                    v[j + d] = v[j];
                }
                else
                {
                    break;
                }
            }
            v[j + d] = tmp;
            /*for (j = i; j >= d; j -= d)
            {
                if (tmp < v[j-d])
                {
                    v[j] = v[j - d];
                }
                else
                {
                    break;
                }
            }
            v[j] = tmp;*/
        }
    }
}
int main()
{
    vector<int> v(10);
    int n(0);
    cin >> n;
    v.resize(n);
    for (auto &a : v)
    {
        cin >> a;
    }
    Shell_Sort(v);
    for (auto a : v)
    {
        cout << a << ' ';
    }
    return 0;
}
/*
6
3 1 7 5 2 4
*/