C_C++算法_堆排序

堆排序

特点

堆是非线性数据结构,相当于一维数组,有两个直接后继。堆通常是一个可以被看做一棵树的数组对象,堆总是满足两个条件堆中某个结点的值总是不大于或不小于其父结点的值堆总是一棵完全二叉树

堆排序的最典型应用就是优先队列,根结点最大的堆叫做大顶堆根结点最小的堆叫做小顶堆。因此,二叉堆排序是在插入元素删除元素的时候进行的。堆是一个一维数组,同时也是一棵完全二叉树。因此,可以将堆按照从上到下从左到右的顺序将数组的索引号与树的各个节点进行映射,如下所示:

二叉堆数组索引映射

具体映射关系是任意父节点左边的索引号是自身的2倍,而任意父节点右边的索引号是自身索引号的2倍 + 1

添加数据思路

基于堆的特点当新的元素加入到队尾时,该元素将与自身父节点进行比较,大于父节点则进行交换。

添加代码

template<typename Item>
class MaxHeap {
private:
    Item *  item_heaps_;
    int     count_;

private:
    void shiftUp(int _index) {
        while (_index > 1 && item_heaps_[_index / 2] < item_heaps_[_index]) {
            // item_heaps_[_index / 2] 表示当前节点的父节点位置
            std::swap(item_heaps_[_index / 2], item_heaps_[_index]);
            _index /= 2;
        }
    }
public:
    MaxHeap(int _capacity) {
        item_heaps_ = new Item[_capacity + 1];
        count_ = 0;
    }
    ~MaxHeap() {
        delete [] item_heaps_;
    }
    void insert(Item _item) {
        item_heaps_[++count_] = _item;
        shiftUp(count_);
    }
};

删除数据思路

首先队列只能从第一个元素开始删除,在删除时现将第一个元素与最后一个元素进行交换,用交换后的第一个元素与子节点进行比较,左右两边的节点哪个节点元素大就与哪边的元素进行交换,交换后继续用此元素进行比较,直到均大于子节点为止。

删除数据代码

template<typename Item>
class MaxHeap {
private:
    Item *  item_heaps_;
    int     count_;
private:
    void shiftDown(int _index) {
        while (_index * 2 <= count_) {
            int swap_index = _index * 2;
            if (swap_index + 1 <= count_ && (item_heaps_[swap_index + 1] > item_heaps_[swap_index])) {
                // 左边的节点大于右边的节点,则准备与左边的换
                swap_index += 1;
            }

            if (item_heaps_[swap_index] < item_heaps_[_index]) {
                // 当前的节点大于准备要交换的节点,则不再循环
                break;
            }

            std::swap(item_heaps_[swap_index], item_heaps_[_index]);
            _index = swap_index;
        }
    }

public:
    MaxHeap(int _capacity) {
        item_heaps_ = new Item[_capacity + 1];
        count_ = 0;
    }
    ~MaxHeap() {
        delete [] item_heaps_;
    }
    Item extract() {
        Item max_item = item_heaps_[1];
        std::swap(item_heaps_[1], item_heaps_[count_--]);
        shiftDown(1);
        return max_item;
    }
};

索引堆

排序的稳定性

排序的稳定性体现在当数组中存在数值相等时,排序前后的相对位置不发生变换,如下所示,排序前后12这个元素的位置先后顺序没有发生改变。
排序稳定性
为了解决堆排序时数据的不稳定性可以使用索引堆,增加一个数据的索引映射。

template<typename Item>
class IndexHeap {
private:
    Item *  item_heaps_;
    int *   indexes_;
    int     count_;
private:
    void shiftUp(int _index) {
        while (_index > 1 && item_heaps_[indexes_[_index / 2]] < item_heaps_[indexes_[_index]]) {
            // item_heaps_[_index / 2] 表示当前节点的父节点位置
            std::swap(indexes_[_index / 2], indexes_[_index]);
            _index /= 2;
        }
    }
    void shiftDown(int _index) {
        while (_index * 2 <= count_) {
            int swap_index = _index * 2;
            if (swap_index + 1 <= count_ && (item_heaps_[indexes_[swap_index + 1]] > item_heaps_[indexes_[swap_index]])) {
                // 左边的节点大于右边的节点,则准备与左边的换
                ++swap_index;
            }

            if (item_heaps_[indexes_[swap_index]] < item_heaps_[indexes_[_index]]) {
                // 当前的节点大于准备要交换的节点,则不再循环
                break;
            }

            std::swap(indexes_[swap_index], indexes_[_index]);
            _index = swap_index;
        }
    }
public:
    IndexHeap(int _capacity) {
        item_heaps_ = new Item[_capacity + 1];
        indexes_ = new int [_capacity + 1];
        count_ = 0;
    }
    ~IndexHeap() {
        delete [] item_heaps_;
        delete [] indexes_;
    }
    bool isEmpty() {
        return count_ == 0;
    }
    int size() {
        return count_;
    }
    void insert(Item _item) {
        item_heaps_[++count_] = _item;
        indexes_[count_] = count_;
        shiftUp(count_);
    }
    Item extract() {
        Item max_item = item_heaps_[indexes_[1]];
        std::swap(indexes_[1], indexes_[count_--]);
        shiftDown(1);
        return max_item;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个用C++编写的堆排序算法的示例: ```cpp #include <iostream> using namespace std; // 交换两个元素的位置 void swap(int& a, int& b) { int temp = a; a = b; b = temp; } // 调整堆,使其满足堆性质 void heapify(int arr[], int n, int i) { int largest = i; // 初始化最大元素为根节点 int left = 2 * i + 1; // 左子节点的索引 int right = 2 * i + 2; // 右子节点的索引 // 如果左子节点大于根节点,则更新最大元素的索引 if (left < n && arr[left] > arr[largest]) { largest = left; } // 如果右子节点大于当前最大元素,则更新最大元素的索引 if (right < n && arr[right] > arr[largest]) { largest = right; } // 如果最大元素的索引不是根节点的索引,则交换根节点和最大元素 if (largest != i) { swap(arr[i], arr[largest]); // 递归调整交换后的子树 heapify(arr, n, largest); } } // 堆排序函数 void heapSort(int arr[], int n) { // 构建最大堆,从最后一个非叶子节点开始调整 for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } // 逐个将堆顶元素移到末尾,并调整堆 for (int i = n - 1; i >= 0; i--) { swap(arr[0], arr[i]); heapify(arr, i, 0); } } int main() { int arr[] = { 12, 11, 13, 5, 6, 7 }; int n = sizeof(arr) / sizeof(arr[0]); cout << "原始数组:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; heapSort(arr, n); cout << "排序后的数组:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值