一、选择排序

选择出数组中的最小元素,将它与数组的第一个元素交换位置。再从剩下的元素中选择出最小的元素,将它与数组的第二个元素交换位置。不断进行这样的操作,直到将整个数组排序。进行的操作次数 n*(n-1)/2

int main() {
    vector<int> arr = { 5,7,2,4,9,8,0,1,3,6 };
    for (int i = 0; i < arr.size() - 1; i++) {
        int minn = arr[i],index=i;
        for (int j = i+1; j < arr.size(); j++) {
            if (arr[j] < minn) {
                minn = arr[j];
                index = j;
            }
        }
        arr[index] = arr[i];
        arr[i] = minn;
    }
    for (int i = 0; i < arr.size(); i++) cout << arr[i];
    return 0;
}

二、冒泡排序

从左到右不断交换相邻逆序的元素,在一轮的循环之后,可以让未排序的最大元素上浮到右侧。在一轮循环中,如果没有发生交换,就说明数组已经是有序的,此时可以直接退出。需要最多的操作次数 n*(n-1)/2

int main() {
    vector<int> arr = { 5,7,2,4,9,8,0,1,3,6 };
    for (int i = arr.size()-1; i>0; i--) {
        int flag = 0;
        for (int j = 0; j < i; j++) {
            if (arr[j] > arr[j + 1]) {
                //用异或进行元素交换
                arr[j] = arr[j] ^ arr[j + 1];
                arr[j+1] = arr[j] ^ arr[j + 1];
                arr[j] = arr[j] ^ arr[j + 1];
                flag = 1;
            }
        }
                 //在一轮循环中没有进行元素交换,说明当前数组已经有序
        if (flag == 0) break;
    }
    for (int i = 0; i < arr.size(); i++) cout << arr[i];
    return 0;
}

三、插入排序

每次都将当前元素插入到左侧已经排序的数组中,使得插入之后左侧数组依然有序。最坏的情况是数组是倒序的,需要进行 n(n-1)/2次比较和 n(n-1)/2次交换,最好的情况是数组已经是有序的,需要进行n-1次比较和0次交换。插入排序每次只能交换相邻元素,令逆序数量减少 1,因此插入排序需要交换的次数为逆序数量

int main() {
    vector<int> arr = { 5,7,2,4,9,8,0,1,3,6 };
    for (int i = 1; i < arr.size(); i++) {
        for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
            arr[j] = arr[j] ^ arr[j + 1];
            arr[j+1] = arr[j] ^ arr[j + 1];
            arr[j] = arr[j] ^ arr[j + 1];
        }
    }
    for (int i = 0; i < arr.size(); i++) cout << arr[i];
    return 0;
}

四、希尔排序

插入排序每次只能交换相邻的逆序元素,对于大规模的数组,排序很慢。希尔排序则是通过交换不相邻的元素,每次可以将逆序数量减少大于 1,加快了排序速度。

int main() {
    vector<int> arr = { 5,7,2,4,9,8,0,1,3,6 };
    int h = arr.size() / 2;//需要设置希尔常量
    while (h) {
        for (int i = h; i < arr.size(); i++) {
            for (int j = i - h; j >= 0 && arr[j] > arr[j + h]; j -= h) {
                arr[j] = arr[j] ^ arr[j + h];
                arr[j+h] = arr[j] ^ arr[j + h];
                arr[j] = arr[j] ^ arr[j + h];
            }
        }
        h /= 2;
    }
    for (int i = 0; i < arr.size(); i++) cout << arr[i];
    return 0;
}

五、归并排序

将待排序的数组不断地分成两部分,对不同部分的元素分别进行排序,然后归并起来。(空间复杂度为什么是n)

vector<int> merge(vector<int>&a, vector<int>&b) {
    if (a.empty()) return b;
    else if (b.empty()) return a;
    else {
        vector<int> res;
        int a1 = a.size(), b1 = b.size(), i = 0, j = 0;
        while (i < a1&&j < b1) {
            if (a[i] < b[j]) {
                res.push_back(a[i]);
                i++;
            }
            else {
                res.push_back(b[j]);
                j++;
            }
        }
        while (i < a1) {
            res.push_back(a[i]); i++;
        }
        while (j < b1) {
            res.push_back(b[j]); j++;
        }
        return res;

    }
}
vector<int> fun(vector<int> &array, int l, int r) {

    if (l > r) {
        vector<int> t = {};
        return t;
    }
    if (l == r) {
        vector<int> t;
        t.push_back(array[l]);
        return t;
    }
    else {
        vector<int> left = fun(array, l, (l + r) / 2);
        vector<int> right = fun(array, (l + r) / 2 + 1, r);
        return merge(left,right);

    }
}
int main() {
    vector<int> arr = { 5,7,2,4,9,8,0,1,3,6 };
    int l = 0, r = arr.size() - 1;
    vector<int> res = fun(arr, l, r);
    for (int i = 0; i < res.size(); i++) cout << res[i];
    return 0;
}

六、快速排序

首先从待排序的数组中选择一个元素作为比较的基准,然后遍历一遍数组,将所有比这个值小的元素放到左边,比这个值大的元素放到右边,最后分别对左边和右边的元素重复上述过程,直到所有元素都排好序

void quickSort(vector<int>&a, int low, int high)
{
    if (low < high)  //判断是否满足排序条件,递归的终止条件
    {
        int i = low, j = high;   //把待排序数组元素的第一个和最后一个下标分别赋值给i,j,使用i,j进行排序;
        int x = a[low];    //将待排序数组的第一个元素作为哨兵,将数组划分为大于哨兵以及小于哨兵的两部分                                   
        while (i < j)
        {
            while (i < j && a[j] >= x) j--;  //从最右侧元素开始,如果比哨兵大,那么它的位置就正确,然后判断前一个元素,直到不满足条件
            if (i < j) a[i++] = a[j];   //把不满足位次条件的那个元素值赋值给第一个元素,(也即是哨兵元素,此时哨兵已经保存在x中,不会丢失)并把i的加1
            while (i < j && a[i] <= x) i++; //换成左侧下标为i的元素开始与哨兵比较大小,比其小,那么它所处的位置就正确,然后判断后一个,直到不满足条件
            if (i < j) a[j--] = a[i];  //把不满足位次条件的那个元素值赋值给下标为j的元素,(下标为j的元素已经保存到前面,不会丢失)并把j的加1
        }
        a[i] = x;   //完成一次排序,把哨兵赋值到下标为i的位置,即前面的都比它小,后面的都比它大
        quickSort(a, low, i - 1);  //递归进行哨兵前后两部分元素排序 , low,high的值不发生变化,i处于中间
        quickSort(a, i + 1, high);
    }
}
int main() {
    vector<int> arr = { 5,7,2,4,9,8,0,1,3,6 };
    int l = 0, r = arr.size() - 1;
    quickSort(arr, l, r);
    for (int i = 0; i < arr.size(); i++) cout << arr[i];
    return 0;
}

七、堆排序

首先将待排序序列构造成一个大根堆,将根节点与末尾元素交换,此时末尾就为最大值,然后将剩下的前n-1个元素重新构造大根堆,并将该根节点与倒数第二个数交换得到第二大的数字,如此反复循环,最终得到一个有序序列。

void adjuct(vector<int>&arr, int i,int len) {
    int l = i * 2 + 1;
    int r = i * 2 + 2;
    //找出当前节点与它的左右孩子节点中值最大的节点
    int index = i, maxval = arr[i];
    if (l<len && arr[l]>maxval) { maxval = arr[l]; index = l; }
    if (r<len && arr[r]>maxval) { maxval = arr[r]; index = r; }
    if (index != i) {
        //调整节点并递归
        arr[index] = arr[i];
        arr[i] = maxval;
        adjuct(arr, index,len);
    }
}
int main() {
    vector<int> arr = { 5,7,2,4,9,8,0,1,3,6 };
    //1.建堆,自下而上
    int len = arr.size();
    for (int i = len / 2 - 1; i >= 0; i--) adjuct(arr, i,len);
    //2.排序
    for (int i = len - 1; i > 0; i--) {
        int tmp = arr[i];
        arr[i] = arr[0];
        arr[0] = tmp;
        adjuct(arr, 0, i);
    }

八、桶排序

将待排序序列中处于同一个值域的元素存入同一个桶中,则拆分后形成的多个桶,从值域上看是处于有序状态的。对每个桶中元素进行排序,则所有桶中元素构成的集合是已排序的。
##九、性能复杂度比较
图片说明