选择:每次选出一个合法(最大/最小)的数据放到其最终应该在的位置
1.(简单)选择排序:每趟从待排序区中,选择一个最小的数,放到待排序区的第一个位置,从而实现升序排列。
时间复杂度:O(n^2)
是否稳定:不稳定
为就地排序

2.对选择排序进行优化---->堆排序

对于一棵完全二叉树,进行编号,编号规则为:根节点为1,然后从上到下,从左到右。除根节点外,节点i的父亲节点编号为i/2(向下取整)。除叶子节点外,节点i的左孩子节点编号为2*i,右节点为2*i+1(可直接用数组存储)

堆(Heap):是一类基于完全二叉树的特殊数据结构

1.大顶堆:在大顶堆中,根节点的值必须大于等于其孩子节点的值,且所有子树均满足
2.小顶堆:在小顶堆中,根节点的值必须小于等于其孩子节点的值,且所有子树均满足

1.建堆:用一个数组保存 
(1)自我初始化:在原数组基础上进行初始化
    从子树入手,由小及大去调整每棵子树(不包含叶子节点):
    对于每棵子树,我们向下调整:
    让根节点和其左右孩子作比较,最小值和根节点交换,继续向下调整子树
(2)通过插入建堆
    数组中每多一个数据就调整一次,新插入的数据放在最后,如果其比父亲大或者新插入的数据是根节点就不用调整,否则就向上调整

堆排序:
(1)建堆
(2)循环n次,每次输出最小数---->a[0]
(3)删掉a[0]---->让堆中最后一个节点替换a[0],然后重新对a[0]向下调整

时间复杂度:O(nlogn)
是否稳定:不稳定
为就地排序


堆的应用:
1.优先队列:基于堆
2.1亿个数,选出前一百个最大的数,不能使用大顶堆,使用小顶堆
a[100]--->堆
先读入100个数,建立小顶堆
接下来,当读入一个数x时,如果x<=a[0],直接读入下一个数
否则a[0]=x,向下调整小顶堆
最后留下来的小顶堆就是答案


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
using namespace std;
//i为根节点下标
void Down_Adjust(vector<int>(&v), int i,int size)
{
    int parent(i);//根节点下标
    int l_child(2 * i);//左孩子下标
    int tmp(0);
    //因为调整后可能子树不再是小顶堆,所以循环向下调整
    while (parent * 2 <= size)
    {
        l_child = 2 * parent;
        if (l_child + 1 <= size && v[l_child + 1] < v[l_child])
        {
            l_child = l_child + 1;
        }
        //此时,l_child是值较小的孩子
        if (v[parent] < v[l_child])
        {
            break;
        }
        else
        {
            tmp = v[l_child];
            v[l_child] = v[parent];
            v[parent] = tmp;
            parent = l_child;
        }
    }
}
void Up_Adjust(vector<int>(&v),int i)
{
    int tmp(0);
    int child(i);
    int parent(0);
    //不是根节点就继续调整
    while (child > 1)
    {
        parent = child / 2;
        if (v[parent] < v[child])
        {
            break;
        }
        else
        {
            tmp = v[parent];
            v[parent] = v[child];
            v[child] = tmp;
            child = parent;
        }
    }
}
void Heap_Sort(vector<int>(&v))
{
    //1.建堆
    //(1)自我初始化

    /*for (int i = (v.size() - 1) / 2; i >= 1; --i)//枚举每一个子树根节点
    {
        Down_Adjust(v, i,v.size() - 1);
    }*/
    for (int i = 1; i < v.size(); ++i)
    {
        cout << v[1] << ' ';
        //每次“删除”最后一个节点
        v[1] = v[v.size() - i];
        Down_Adjust(v, 1, v.size() - 1 - i);
    }
}
void Selection_Sort(vector<int>(&v))
{
    //排n-1趟
    for (int i = 0; i < v.size() - 1; ++i)
    {
        int min_i(i);//最小数下标
        int tmp(0);
        for (int j = i; j < v.size(); ++j)
        {
            if (v[j] < v[min_i])
            {
                min_i = j;
            }
        }
        tmp = v[i];
        v[i] = v[min_i];
        v[min_i] = tmp;
    }
}
int main()
{
    vector<int> v;
    int n(0);
    cin >> n;
    //下标从1开始,方便建堆
    v.resize(n+1);
    //(2)插入建堆
    for (int i = 1;i<v.size();++i)
    {
        cin >> v[i];
        Up_Adjust(v,i);
    }
    Heap_Sort(v);
    /*for (auto a : v)
    {
        cout << a << ' ';
    }*/
    return 0;
}
/*
6
6
2
3
5
1
4
*/