算法导论 - 堆排序

注意:为了更好的学习理解,本文实现了MATLAB程序,本文图示大部分是书籍的截图,因为书籍中的图示和解释非常严谨、非常详细、非常棒!

 

                                          堆排序

目录

一、引言

二、维护堆的性质

三、建堆

四、堆排序算法

五、优先队列

六、参考文献

 

 

一、引言

  • 1. 什么是堆?

如上图所示,(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树,树上的每一个节点对应数组中的一个元素。除了底层外,该树是完全充满的,而且是从左向右填充。

  • 2.  二叉堆的两种形式:最大堆、最小堆

最大堆:最大堆的性质是指除了根以外的所有结点i都要满足:A[PARENT(i)] \geq A[i],也就是说,某个结点的值至多与其父节点一样大。因此,堆中的最大元素存放在根节点中;并且在任意一子树中,该子树所包含的所有结点的值都不大于该子树根节点的值。

最小堆:最小堆的性质是指除了根以外的所有结点i都要满足:A[PARENT(i)] \leq A[i],也就是说,最小堆的组织方式跟最大堆的相反,最小堆中的最小元素放在根节点中。

  • 3. 完全二叉树?

 

如上图所示,除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐

  • 4. 堆的应用?

堆的应用比较广泛,概括一下主要用在以下几个方面,内存管理、数据处理、系统中内核和驱动事件优先级管理等等。

 

二、维护堆的性质

  •  1. 获取父节点下标
function index = parent(i)
    index =  i/2;
end
  • 2. 获取左孩子下标
function index = left(i)
    index = 2*i;
end
  • 3. 获取右孩子下标
function index = right(i)
    index = 2*i + 1;
end
  • 4. 维护最大堆性质

如上图所示,实现代码如下:

% 1. 最大堆性质维护,可以理解为修正为最大堆
function [A_t] = max_heapify(A, i, n)
    l = left(i);              % (1) 获取左下标
    r = right(i);             % (2) 获取右下标
    
    if l <= n && A(l) > A(i)        % (3) 判断左孩子是否大于父节点
        largest = l;
    else
        largest = i;
    end
    
    if r <= n && A(r) > A(largest)  % (4) 判断右节点是否大于父节点
        largest = r;
    end
    
    if largest ~= i                 % (5) 如果子节点大于父节点则交换值
        temp = A(i);
        A(i) = A(largest);
        A(largest) = temp;
        A = max_heapify(A, largest, n);
    end
    A_t = A;
end
  • 5. 维护最小堆性质
function [A_t] = min_heapify(A, i, n)
    l = left(i);              % (1) 获取左下标
    r = right(i);             % (2) 获取右下标
    
    if l <= n && A(l) < A(i)        % (3) 判断左孩子结点是否大于父结点
        largest = l;
    else
        largest = i;
    end
    
    if r <= n && A(r) < A(largest)  % (4) 判断右孩子结点是否大于父结点
        largest = r;
    end
    
    if largest ~= i                 % (5) 如果有则交换值
        temp = A(i);
        A(i) = A(largest);
        A(largest) = temp;
        A = max_heapify(A, largest, n);
    end
    A_t = A;
end

 

三、建堆

  •  1. 创建最大堆

如上图,程序如下:

function [ Y ] = build_max_heap( A )
%   创建最大堆

    [m, n] = size(A);               % (1). 获取堆数组的大小
    for i = floor(n/2):-1:1         % (2). 自底向上的方法利用max_heapify转换A为最大堆
        A = max_heapify(A, i, n);
    end
    Y = A;
end
  • 2. 创建最小堆
function [ Y ] = build_min_heap( A )
%   创建最小堆

    [m, n] = size(A);               % (1). 获取堆数组的大小
    for i = floor(n/2):-1:1         % (2). 自底向上的方法利用max_heapify转换A为最小堆
        A = max_heapify(A, i, n);
    end
    Y = A;
end

 

四、堆排序算法

function [A_t] = heap_sort(A)
    A = build_max_heap(A);      % (1). 创建最大堆
    [m,n] = size(A);
    for i = n:-1:2              % (2). 重复调用max_heapify函数,构造新的最大堆
        temp = A(1);
        A(1) = A(i);
        A(i) = temp;
        n = n - 1;
        A = max_heapify(A,1,n);
    end
    A_t = A;
end

 

五、优先队列

优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,称为关键字(key);普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆数据结构来实现。

优先队列主要应用在任务和事件的调度上(优先级)。

  • 1.  插入元素
function [A_t] = max_heap_insert(A, key)
% 把元素插入到集合A中
    [m,n] = size(A);
    A(n) = -10000;
    A_t = heap_increase_key(A, n, key);
end
  • 2. 检索具有最大键字的元素
function x = heap_maximum(A)
% 对于最大优先队列
    x = A(1);
end
  • 3. 检索并删除具有最大键字的元素
function [index_max, A_t] = heap_extract_max(A)
%   去掉并返回S中的具有最大关键字的元素
    [m, n] = size(A);
    if n < 1
        disp('heap underflow');
    end
    index_max = A(1);
    A(1) = A(n);
    A(n) = A(n-1);
    A = max_heapify(A,1,n);
    A_t = A;
end
  • 4. 将元素x的关键字值增加到k
function [A] = heap_increase_key(A,i,key)
%   将元素x的关键字值增加到k,这里假设k的值不小于x的原关键字值
    if key < A(i)
        disp('error : new key is smaller than current key');
    end
    A(i) = key;
    while i > 1 && A(parent(i)) < A(i)
        A(i) = A(parent(i));
        i = parent(i);
    end
end

六、参考文献

  • [1] 算法导论(第三版)
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法导论 第3版》是一本经典的计算机科学教材,由Thomas H.Cormen、Charles E.Leiserson、Ronald L.Rivest和Clifford Stein合著,主要介绍了算法设计与分析的基本原理和技巧。 这本教材分为六个部分,共29章。第一部分概述了算法设计与分析的基本概念和方法。第二部分介绍了基本的排序和选择算法,包括插入排序、归并排序、堆排序等。第三部分讨论了数据结构,包括栈、队列、二叉树等,以及各种基本数据结构的实现和应用。第四部分重点介绍了动态规划算法和贪心算法,涵盖了最长公共子序列、最优二叉查找树等问题。第五部分深入讲解了图算法,包括最短路径、最小生成树等。第六部分介绍了一些高级主题,如NP完全性以及近似算法。 每一章都包含了大量的例子和习题,这些习题有助于读者巩固知识,并提供了解决实际问题的思路。此外,书中还有丰富的附录和参考资料,供读者进一步学习和探索。 《算法导论 第3版》有着简洁明了的表达和深度而完整的内容,适合作为大学本科生和研究生学习计算机科学基础的教材。无论是作为算法入门的起点,还是作为算法设计与分析的参考书,都具有很高的价值。 总之,《算法导论 第3版》是一本经典权威的算法教材,涵盖了算法设计与分析的基础知识和方法,并提供了大量的例子和习题,对计算机科学相关专业的学生和从业者来说,是一本不可多得的学习资料。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值