【PAT甲级 堆排序/折半插入排序】1098 Insertion or Heap Sort (25 分)

堆排序和插入排序都使用algorithm中的函数

# include <bits/stdc++.h>
using namespace std;

vector<int> A;
vector<int> A_origin;
vector<int> seq;
int N;
bool isInsertSort = false;
bool isHeapSort = false;

bool isSameArray() {
    for(int i = 1;i <= N;++i)
        if(A[i] != seq[i])
            return false;
    return true;
}

void insertSort() {
    for(int i = 2;i <= N;++i){
        // 检查这一次的排序中途序列是否符合seq(因为最后一步就是完成排序成为有序序列的一步,所以判断这一步可以放在前面)
        isInsertSort = (isSameArray() && i != 2); // 是中间步骤与seq相同而不是初始步骤,所以排除i=2的初始情况
        
        sort(A.begin() + 1, A.begin() + i + 1); // 使用sort函数完成有序部分的排序
        
        // 输出下一趟排序
        if(isInsertSort){
            cout << "Insertion Sort\n";
            for(int k = 1;k <= N;++k)
                cout << A[k] << (k == N?"\n":" ");
            return;
        }
    }
}

void heapSort() {
    make_heap(A.begin()+1, A.end());
    for(int i = N;i > 1;--i){
        isHeapSort = (isSameArray() && i != N);  // 是中间步骤与seq相同而不是初始步骤,所以排除i=N的初始情况

        pop_heap(A.begin()+1, A.begin()+1 + i); // 这个pop_heap库函数只是将堆顶元素放到数组尾部,然后再从堆顶向下调整

        if(isHeapSort){
            cout << "Heap Sort\n";
            for(int k = 1;k <= N;++k)
                cout << A[k] << (k == N?"\n":" ");
            return;
        }
    }
}

int main() {
    cin >> N;
    A.resize(N+1);
    seq.resize(N+1);
    for(int i = 1;i <= N;++i)
        cin >> A[i];
    for(int i = 1;i <= N;++i)
        cin >> seq[i];
    A_origin = A;

    insertSort();
    A = A_origin; // 复原A
    heapSort();
    
    return 0;
}

自己写函数建堆并进行堆排序

# include <bits/stdc++.h>
using namespace std;

vector<int> A;
vector<int> A_origin;
vector<int> seq;
int N;
bool isInsertSort = false;
bool isHeapSort = false;

bool isSameArray() {
    for(int i = 1;i <= N;++i)
        if(A[i] != seq[i])
            return false;
    return true;
}

void insertSort() {
    for(int i = 2;i <= N;++i){
        // 检查这一次的排序中途序列是否符合seq(因为最后一步就是完成排序成为有序序列的一步,所以判断这一步可以放在前面)
        isInsertSort = (isSameArray() && i != 2); // 是中间步骤与seq相同而不是初始步骤,所以排除i=2的初始情况

        // 可以自己写,也可以直接用sort函数
        if(A[i] < A[i-1]){ // 如果待插入元素 < 有序序列的最小元素,说明需要进行插入,否则这一步已经自然完成了插入(自然地插入到了有序序列最后)
            A[0] = A[i]; // 使用A[0]哨兵保存待插入元素
            int pos = lower_bound(A.begin(), A.begin()+i-1, A[0]) - A.begin(); // 记得减A.begin()
            for(int j = i-1;j >= pos;--j) // 将A[i]到插入位置前的元素后移以腾出插入位置并覆盖待插入元素原本的位置(待插入元素已被A[0]保存)
                A[j+1] = A[j];
            A[pos] = A[0];
        }
        // sort(A.begin() + 1, A.begin() + i + 1);
        
        // 输出下一趟排序
        if(isInsertSort){
            cout << "Insertion Sort\n";
            for(int k = 1;k <= N;++k)
                cout << A[k] << (k == N?"\n":" ");
            return;
        }
    }
}

void downAdjust(int low, int high) {
    int i = low; // 待调整节点
    int j = 2 * i; // 待调整节点的左孩子
    while(j <= high) { // 
        if(j + 1 <= high  && A[j+1] > A[j]) // 使得j指向i的值较大的孩子
            j++;
        if(A[j] > A[i]) { // 大根堆,如果孩子的值比父节点的大,那就要调整
            swap(A[i], A[j]);
            i = j;
            j = 2 * i;
        } else 
            break;
    }
}

void creatMaxHeap(){
    for(int i = N/2;i >= 1;--i) // 从最后一个非叶子结点到根节点进行向下调整以使得整个序列堆化
        downAdjust(i, N);
}

void heapSort() {
    // make_heap(A.begin()+1, A.end());
    creatMaxHeap();
    for(int i = N;i > 1;--i){
        isHeapSort = (isSameArray() && i != N);  // 是中间步骤与seq相同而不是初始步骤,所以排除i=N的初始情况

        // pop_heap(A.begin()+1, A.begin()+1 + i); // 这个pop_heap库函数只是将堆顶元素放到数组尾部,然后再从堆顶向下调整
        swap(A[1], A[i]); // 交换末尾节点和根节点(最值节点)
        downAdjust(1, i-1); // 从根节点向下调整

        if(isHeapSort){
            cout << "Heap Sort\n";
            for(int k = 1;k <= N;++k)
                cout << A[k] << (k == N?"\n":" ");
            return;
        }
    }
}


int main() {
    cin >> N;
    A.resize(N+1);
    seq.resize(N+1);
    for(int i = 1;i <= N;++i)
        cin >> A[i];
    for(int i = 1;i <= N;++i)
        cin >> seq[i];
    A_origin = A;

    insertSort();
    A = A_origin; // 复原A
    heapSort();
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值