C++数据结构的阶段书籍研读以及问题解答 ADT篇

这篇博客是写的《数据结构与算法分析C++版本》这本书的研读与问题解答

背黑白字是和其他结构有所关联的,需要系统的去学习

---------------------------------------------- ADT优先队列的实现-------------------------------------------------------

首先是引入,我们用计算机处理作业时,一般来说我们会优先完成较短的作业,以提高效率。此时涉及到排序,排序易解。但是,有特殊的作业急于优先完成,这些作业拥有优先权。

这种特殊的应用,需要一类特殊的队列,也就是优先队列,优先队列的学习有三个最终目的:

1.优先队列ADT的有效实现

2.优先队列的使用

3.优先队列的高级实现

--------------------------------------------------=-=--------------------------------------------------------------------------

基本模型也就是我们所想要拥有的基本功能

insert 插入  

deleteMin删除最小者(找出返回并删除队列中最小元素)

基础的就这两个,复杂的后面会学得到。其次在实现的时候也会衍生多种方案。

======================= ======= ===qwq====================================

简单的实现

简单的实现,遍历

  两种想法,一为在表头以O(1)执行插入操作,遍历链表执行删除,时间O(N)。二是让链表保持排序状态,插入耗时O(N)但是删除仅需要O(1)。基于删除的操作从不多于插入的操作的事实,前者是更好的想法。但我通读了这一章的内容,似乎大多用的是第二种类似的实现。

另一种简单的实现,使用二叉查找树

问:二叉查找树是什么?

书上描述二叉查找树过于浪费资源,因为多了许多不需要的操作。

并且在此说明了,实现优先队列以支持合并这个功能。复杂的链表结构去实现他。

==============================qwq========================================

                                                                          二叉堆

一种实现优先队列的工具。简称堆。

两个性质:结构性,堆序性(在执行操作时,应当不破坏这两种性质)

结构性质

完全被填满的二叉树结构,底层从左往右依次填入。也就是说,底层可能不满。也叫做完全二叉树。

高为h的完全二叉树有2^{h}2^{h+1}-1个节点。也就是说有N个元素的完全二叉树高为logN,为             O(logN)

对于任意位置i上的元素,左儿子在2i上,有儿子在2i+1上,父亲在二分之i上。极具有规律,遍历操作极为简单。

’实现代码我会存在另一篇博客里‘

堆序性质

使操作被快速执行即是堆序性质。我们想要快速找到最小元素,不妨设想把最小值放在根上,使所有的节点都小于其后裔,使其获得普遍规律性。

此时书上讲得以常数时间得到附加操作findMin即获得最小元总在根上找到

问:findMin具体是指得什么

-----------------------------------=-=-----------------------------------------------------------------------------------------

基本的堆操作

insert插入

我们依据结构性在下一个可用的位置建立一个空位,即在底层以左往右建立一个新的空的位置用以插入操作。插入的元素与此空位的父亲比较,若小于父亲,则空位朝根的方向移动一位,与父亲交换位置(不是交换元素,此时元素未插入,后面会将为什么)。直到找到空穴位置的父亲大于插入树,此时将元素插入空位,即完成insert插入操作。

这种策略叫做上滤操作

我们也可以用元素的交换实现上滤的操作,但是元素交换涉及3条语句,上滤n层,赋值操作有3n次。但是我们仅仅使将空穴的位置向上推移,最后只有n次上推以及1次的放入元素。

’实现代码我会存在另一篇博客里‘

deleteMin删除

因为堆序性找出最小元是很简单的,即在根这个位置。重点是删除后保持堆序性。

我们删除根最小元后在根再次建立一个空位置,效仿插入操作,将该位置的儿子与堆底层最后一个元素比较,空位置像较小位置滑落,较小值被推上,如果最后一个位置为最小的元素,将此元素放入空穴。避免三次的赋值交换,利用堆序性来向下压空穴,将小值向上推的方法叫做下滤操作

tip:当存在偶数个元素的时候,会有一个节点只有一个儿子,此时需要有个附加测试使此节点假设有两个儿子,在代码上会实现测试

此两种操作的时间都以常数时间完成,最劣O(logN)。

----------------------------------------------------qwq-----------------------------------------------------------------------

其余堆操作

因为我们为了实现最优这个条件,设计最小堆这种堆。但在求最大元的方面无能为力,因为最大的元素始终在树叶上,当堆的元素变多之后,树叶所占的比例会变得无比庞大。

一个堆所蕴含的信息太少,找到特定的元素所耗费的时间漫长。因此我们要用到如散列表等某些其他的数据结构。

问:什么是散列

前提:此时我们用其他的方法得知每一个元素的位置,有几种操作的开销变小,可以尝试运行一下哎。

decreaseKey降低关键字的值

decreaseKey(p,\Delta)操作降低在p处的值,降值的幅度为正的量\Delta。因为此操作可能会破坏堆的性质,所以还需用上滤法调整。该操作对系统管理程序有用,可以调整优先级

increaseKey增加关键字的值

实现方法与降低类似。许多调度程序自动的降低正在过多消耗CPU时间的进程的优先级。

remove删除

remove(p)操作删除堆中p处的节点。该操作首先先执行decreaseKey(p,\infty)然后再执行deleteMin()。很好理解的过程。当一个进程被用户终止的时候,他必须从队列中被除去。

buildHeap构建堆

有时二叉堆是由一些项的一个初始集合构造而成的,以N项作为输入把他们放入堆中。可以使用n个insert完成。总时间最劣为O(NlogN)。此时希望其优化保持线性时间界。

一般算法以N次任意操作放入堆以保持结构特性,之后使用percolateDown(i)从节点i下滤,即可创造一个堆序的树。此时buildHeap的操作运行时间界为O(N)

问:percolateDown是什么操作

6.1证明  :有时间我会来增添解读。

==============================QWQ=======================================

优先队列的应用,在此省略

==============================QWQ=======================================

                                                                   d堆

即是二叉堆的扩展,即每个节点有更多的儿子,不过在很多操作上复杂度会上升很多,最大的优点是可以存储更多的元素。再此章较为省略。

===============================qwq=======================================

                                                                 左氏堆

 我们在此设计一种堆结构可以有效的支持合并操作(即以O(N)时间处理一次merge)。而二叉堆只使用一个数组很困难去实现。我们还是老规矩使用链式数据结构。

左氏堆也具有结构性和有序性。左氏堆也是二叉树,但不但不是平衡的,反而是趋向于极为的不平衡。

我们把任一节点的X的零路径长npl(X),定义为从X到一个不具有两个儿子的节点的最短路径的长。因此,具有0个儿子或有1个儿子的节点的npl为0,而npl(nullptr)=-1。

问:nullptr是什么?

任一节点的零路径长比他的诸儿子节点的零路径长的最小值多1.此结论也适用少于两个儿子的节点。

左氏堆的性质:对于每个节点的X,左儿子的零路径长至少与右儿子的零路径长一样。

此性质即增强了左儿子的倾向性

也是因为此性质,将工作重心放在右路径将会很方便,保证树的深度短。并且对右路径的insert和merge可能会破坏左氏堆的性质也很容易就可以恢复性质。

-------------------------------------------------------orz--------------------------------------------------------------------

左氏堆的基本操作

左氏堆的基本操作是合并,毕竟我们一开始设计此堆的原因便是想完成合并的操作,插入可以看成单节点的插入。

思考:

1,用递归的方式实现合并。最小的元素在根处。两个左氏堆比较根,将较大的根与较小的根的堆右子堆合并。

将此操作重复进行递归运算。虽然最后得到的不是左氏堆,但我们得到的是较小的根值堆右子堆与根值大的堆的合并。因为根值小的右子堆与根值大的堆合并,所以新的零路径长大于左左子堆。

此时新的右子堆是左氏的,原先根小的左子式没有变化。此时我们再交换左儿子与右儿子,之后更新零路径长,就完成了合并的操作。

2.书上原话:非递归的做法容易理解,但编程困难。留给读者去证明:递归过程和非递归的过程的结果是相同的。

在明白了合并之后,插入即可看成单节点的合并。而deleteMin,除掉根,得到新的合并,即可完成。

’实现代码我会存在另一篇博客里‘

---------------------------------------------------QWQ--------------------------------------------------------------------

                                                                     斜堆

斜堆是左氏堆的自调节形式。斜堆是具有堆序性的二叉树,但没有二叉树结构的限制。

并且,任意节点的零路径长的任何信息都不在保留。斜堆的右路径可以任意长,所有操作最劣时间均为O(N),与伸展树类似。对任意M次连续操作,总的最坏的运行时间是O(MlogN)。因此,斜堆每次的操作的摊还开销为O(logN)

斜堆的基本操作也为合并merge。例程也是递归。

但是在合并之后,交换是必然的无条件的。略

==================================qwq====================================

                                                                   二项队列

啧,没时间了。下次一定。

不过估计也只是一种优越的技巧,从维度上还是一个档次的内容。无非是检索和删除操作的便利。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值