概述
與fifo的普通佇列不同,在優先順序佇列中,元素出隊順序是由元素的優先順序決定。比如大根堆是最大的元素先出隊,小根堆是最小的元素先出隊。
堆是實現優先順序佇列效率很高的資料結構(當然我們也可以使用無序的線性表或者有序鍊錶來實現,但是它們的刪除、插入的時間複雜度至少有乙個是o(n))。堆是一棵完全二叉樹,這樣就保證了底層儲存的陣列擁有很高的空間利用率。無論是大根堆還是小根堆,它們的插入和刪除的複雜性都是o(height of tree)也就是o(log n)。
堆的底層實現是陣列,但是邏輯上我們將它對映到一棵完全二叉樹上。它的插入操作是從陣列的末尾的下乙個位置也就是完全二叉樹的下乙個新增的葉子節點開始,逐層遍歷它的父節點、祖父節點…直到找到合適的插入位置或者達到根部。反之,它的刪除操作則是首先將根節點也就是陣列的[0]元素出隊,然後從上到下逐層選擇合適左右孩子進行遍歷。
大根堆的實現
其他例如優先佇列adt或者堆空的自定義異常類等一些輔助類這裡就省略了,它們與以前其他資料結構中的實現大同小異 。
#pragma once
#ifndef maxheap_h
#define maxheap_h
#include
"emptyheap.h"
#include
"priorityqueueadt.h"
//堆空異常 借用了佇列的異常類
#include "..
//..//..///ch09/queue/queue/queueempty.h"
#include "..
//..//..//ch06/chainlist/chainlist/illegalparametervalue.h"
//***********************************最大堆的定義實現***********************************===
template
<
typename t>
class
maxheap
:public priorityqueue
bool
empty()
const
size_t size()
const
t&top()
const
;void
pop();
void
push
(const t& _element)
;void
heapinitial
(t* arr,size_t arrsize)
;//將給定陣列轉為最大堆
void
output
(std::ostream& os)
const
;private
: t* heap;
//優先順序佇列(堆)陣列
size_t capcacity;
//堆的容量
size_t heapsize;
//堆的元素個數};
template
<
typename t>
inline maxheap
::maxheap
(size_t _capacity)
template
<
typename t>
inline t& maxheap
::top()
const
template
<
typename t>
void maxheap
::push
(const t& _element)
size_t pos =
++heapsize;
//要插入的位置
//在完全二叉樹中多出乙個位置為++heapsize的節點,從要插入的元素_element的父節點
//也就是heap[pos/2]開始逐級向上比較,直到找到要插入的元素在大根堆中的位置(大於子節點且小於父節點)
while
(pos !=
1&& heap[pos/2]
<_element)
//比較完成 插入該元素
heap[pos]
= _element;
}template
<
typename t>
void maxheap
::pop()
//找到位置 插入
heap[pos]
= lastelement;
}template
<
typename t>
void maxheap
::heapinitial
(t* arr,size_t arrsize)
//找到合適的插入位置
heap[child /2]
= rootelement;}}
template
<
typename t>
void maxheap
::output
(std::ostream& os)
const
os << endl;
}template
<
typename t>
std::ostream&
operator
<<
(std::ostream& os,
const maxheap
& heap)
#endif
// !maxheap_h
小根堆的實現
小根堆的實現和大根堆的實現一模一樣,只是在插入或者刪除以及堆化乙個給定陣列的時候,對型別t的判斷條件相反。即大根堆如果元素大於其父節點則將父節點下移,而小根堆相反,如果元素小於其父節點則將父節點下移。
#pragma once
#ifndef minheap_h
#define minheap_h
//小根堆跟大根堆的實現一模一樣 只是調整樹結構的時候是將小的放在根節點
//大的元素放在左右節點
#include
"priorityqueueadt.h"
#include
"emptyheap.h"
#include "..
//..//..///ch09/queue/queue/queueempty.h"
//***********************************最小堆的定義實現***********************************===
template
<
typename t>
class
minheap
:public priorityqueue
~minheap()
bool
empty()
const
size_t size()
const
t&top()
const
void
push
(const t& _element)
;void
pop();
void
heapinitial
(t* arr, size_t arrsize)
;//將給定陣列轉為最小堆
void
output
(std::ostream& os)
const
;private
: size_t capacity;
size_t heapsize;
t* heap;};
//插入操作是從下向上依次調整
template
<
typename t>
void minheap
::push
(const t& _element)
//依次向上調整
int pos =
++heapsize;
while
(pos>=
1&& _element < heap[pos /2]
) heap[pos]
= _element;
}//pop操作則是從上到下一次調整
template
<
typename t>
void minheap
::pop()
heap[child /2]
= lastelement;
}//初始化乙個陣列為最小堆 同樣是從上到下進行遍歷調整
template
<
typename t>
void minheap
::heapinitial
(t* arr,size_t arrsize)
heap[child /2]
= rootelement;}}
template
<
typename t>
void minheap
::output
(std::ostream& os)
const
os << endl;
}template
<
typename t>
std::ostream&
operator
<<
(std::ostream& os,
const minheap
& heap)
#endif
// !minheap_h
堆(大根堆 小根堆)
堆又可稱之為完全二叉堆。這是乙個邏輯上基於完全二叉樹 物理上一般基於線性資料結構 如陣列 向量 鍊錶等 的一種資料結構。學習過完全二叉樹的同學們都應該了解,完全二叉樹在物理上可以用線性資料結構進行表示 或者儲存 例如陣列int a 5 就可以用來描述乙個擁有5個結點的完全二叉樹。那麼基於完全二叉樹的...
堆(Heap)大根堆 小根堆
具有以下的特點 1 完全二叉樹 2 heap中儲存的值是偏序 min heap 父節點的值小於或等於子節點的值 max heap 父節點的值大於或等於子節點的值 一般都用陣列來表示堆,i結點的父結點下標就為 i 1 2。它的左右子結點下標分別為2 i 1和2 i 2。如第0個結點左右子結點下標分別為...
堆(Heap)大根堆 小根堆
目錄一般都用陣列來表示堆,i結點的父結點下標就為 i 1 2。它的左右子結點下標分別為2 i 1和2 i 2。如第0個結點左右子結點下標分別為1和2。插入乙個元素 新元素被加入到heap的末尾,然後更新樹以恢復堆的次序。每次插入都是將新資料放在陣列最後。可以發現從這個新資料的父結點到根結點必然為乙個...