堆排序与优先队列(c++实现版)

形成堆:
首先形成堆,我们有两种处理(“上浮”和”下沉”)
上浮:在原堆尾添加元素时,通过比较添加元素和原堆(二叉树)中父节点关系,决定是否继续上浮
下沉:在原堆首添加元素时(此时添加元素是二叉树的根节点),通过比较父节点与左右节点,找出最大的节点,通过是否交换元素,判断是否需要继续下沉
上浮和下沉最坏情况都是lgn,其实就是和二叉树树高有关 T(n) = O(lgn)
总结:两种方法都能形成堆,可是两种方法都有不同使用场景才能发挥其最大威力,
比如:如果向堆集合中添加元素,对于一个序列我们习惯都是在尾部添加(数组,向量(Vector)都是这样),如果我们执意从序列首部添加元素,那未免不得承担将原序列向后挪的性能损失了(因为这是可以避免的,所以我不得不称它为一种”性能损失了”)
所以向原堆添加元素有两种做法:
1.将添加元素放在原堆尾部,采用上浮的做法重新生成堆
2.将添加元素放在原堆首部,采用下沉的做法重新生成堆(其实我上面说有性能损失其实是有问题的,因为计算机中表示序列的一般只有两种
1.顺序存储(数组之流)
2.链式存储(链表之流)
因此上种说法对于链式存储就不适用了(因为添加首元素只需修改指针就可以),此外我下面写的堆排序中是顺序存储结构采用下沉的做法生成堆,因为这种业务不需要挪,所以当我们把添加元素弄到首元素时没有不必要的性能损失时,就是它大放异彩的时候
知道如何形成堆,那么堆排序和优先队列也就不难了
堆排序:

我们首先将输入序列S,通过对所有父节点下沉操作形成堆(因为顺序存储的序列已经给定了,(下沉和上浮性能都无异了)
然后通过将堆的首元素与尾部元素交换,从首元素到新堆尾部元素(上次的堆尾部元素位置 - 1)产生新堆,以此类推,直到无新堆产生
通过操作最大或最小堆获得非递减或非递增序列
性能1.:对于序列大小为n,形成堆时间为O(n * lgn),这个上界不是很紧,读者可以运用自己的聪明才智(一丝丝数学知识)让其紧到O(n)
2.迭代产生新堆:第一步都没紧,我第二步不紧也是O(n * lgn)
综上可知,堆排序最坏情况下T(n) = O(n * lgn)

优先队列:
序列我采用的是顺序存储,每次Insert操作就是上浮的时间(O(lgn)),其他的就没什么可说的了,有说的我会来更

Priority_Queue.h

#pragma once
#include <vector>
#include <iostream>

template<typename V>
class Priority_Queue {
public:
    Priority_Queue() = default;
    ~Priority_Queue() = default;
    Priority_Queue(const std::vector<V>& v);
private:
    std::vector<V> vec;
public:
    void Insert(const V& v);
    V Maximum();
    void Print();
    //V Extract_Max();
private:
    void swim(const int& k) {
        int largest = k;
        while ((largest - 1) / 2 >= 0) {
            int last = largest;
            if (vec[largest] > vec[(last - 1) / 2]) {
                largest = (last - 1) / 2;
                std::swap(vec[largest], vec[last]);
            }else {
                break;
            }
        }
    }
    void sink(const int& lo) {
        int largest = lo;
        while (largest * 2 + 1 >= vec.size() - 1) {
            int last = largest;
            if (vec[larget] < vec[last * 2 + 1]) {
                largest = last * 2 + 1;
            }
            if (last * 2 + 2 <= hi) {
                if (vec[largest] < vec[last * 2 + 2]) {
                    largest = last * 2 + 2;
                }
            }
            if (largest != last) {
                std::swap(vec[largest], vec[last]);
            }
            else {
                break;
            }
        }
    }
};
template<typename V>
Priority_Queue<V>::Priority_Queue(const std::vector<V>& v) {
    for (auto i : v) {
        vec.push_back(i);
        swim(vec.size() - 1);
    }
}
template<typename V>
void Priority_Queue<V>::Insert(const V& v) {
    vec.push_back(v);
    swim(vec.size() - 1);
}
template<typename V>
V Priority_Queue<V>::Maximum() {
    return vec[0];
}
template<typename V>
void Priority_Queue<V>::Print() {
    for (auto& v : vec) {
        std::cout << v << std::ends;
    }
    std::cout << std::endl;
}

main.cpp

#include <stdio.h>
#include <vector>
#include "Priority_Queue.h"
using namespace std;
void sink(vector<int>& vec, const int& lo, const int& hi);
//递归版sink
void keep_max_heap(vector<int>& vec, const int& lo, const int& hi) {
    if (lo * 2 + 1 > hi) {
        return;
    }
    int largest;
    if (vec[lo] < vec[lo * 2 + 1]) {
        largest = lo * 2 + 1;
    }else {
        largest = lo;
    }
    if (lo * 2 + 2 <= hi) {
        if (vec[largest] < vec[lo * 2 + 2]) {
            largest = lo * 2 + 2;
        }
    }
    if (largest != lo) {
        std::swap(vec[largest], vec[lo]);
        keep_max_heap(vec, largest, hi);
    }
}
void make_max_heap(vector<int>& vec) {
    for (int i = vec.size() / 2 - 1; i >= 0; --i) {
        //keep_max_heap(vec, i, vec.size() - 1);
        sink(vec, i, vec.size() - 1);
    }
}
void sink(vector<int>& vec,const int& lo,const int& hi) {
    int largest = lo;
    while (largest * 2 + 1 <= hi) {
        int last = largest;
        if (vec[last] < vec[last * 2 + 1]) {
            largest = last * 2 + 1;
        }
        if (last * 2 + 2 <= hi) {
            if (vec[largest] < vec[last * 2 + 2]) {
                largest = last * 2 + 2;
            }
        }
        if (largest != last) {
            std::swap(vec[largest], vec[last]);
        }else {
            break;
        }
    }
}
void heap_sort(vector<int>& vec) {
    make_max_heap(vec);
    for (int i = vec.size() - 1; i >= 1; --i) {
        std::swap(vec[0], vec[i]);
        keep_max_heap(vec,0,i - 1);
    }
}
void print_vector(const vector<int>& vec) {
    for (auto& v : vec) {
        printf("%d  ", v);
    }
    printf("\n");
}
int main(int argc,char** argv) {
    vector<int> vec{ 0,1,2,3,4,5,6,7,8,9 };
    /*make_max_heap(vec);
    print_vector(vec);
    heap_sort(vec);
    print_vector(vec);*/
    Priority_Queue<int> pq(vec);
    pq.Print();
    pq.Insert(16);
    pq.Insert(10);
    pq.Insert(13);
    pq.Print();
    system("pause");
    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值