實現資料結構:堆。
堆一般使用陣列來表示,其中某個節點下標i的兩個子節點的下標為 2i+1 和 2i+2。堆是一棵完全二叉樹。
堆有3種基本操作:建立,插入,刪除。
這3種操作都需要通過「調整堆」的方式來實現。調整堆是指,對堆中的某個節點,若它的值和它所有子節點相比,不是最大/最小,那麼就需要將最大/最小的元素和當前節點交換,這種操作成為「調整堆」。
建立可以用插入來實現(複雜度o(nlogn)),也可以使用陣列直接轉換成堆(複雜度o(n))。
假設陣列長度為n,那麼這個陣列轉成堆,需要從第乙個有子節點的節點((n - 1)/2或(n - 2)/2開始,倒序「調整堆」,直到下標為0。
插入操作可以先將資料插入到陣列尾部,然後依次調整該資料的父節點,父節點的父節點…直到根節點。
刪除操作可以先將陣列首尾節點互換,然後刪除最後面的元素,最後再調整根節點即可。
/*
* 堆型別
* small 小根堆
* big 大根堆
*/enum heaptype
/* * 堆
*/class heap - arr 建立堆的陣列
* @param - type 堆型別
*/init(arr: [t], type: heaptype = .big)
/** 調整堆:調整以idx為頂的3元素子堆,若頂部元素不是最大/最小,則調整為最大/最小
* @param - idx 表示調整以idx為頂的3元素子堆
* @return - 調整成功返回true,無需調整返回false
*/@discardableresult
private func _adjust(_ idx: int) -> bool
let leftidx = 2 * idx + 1;
let rightidx = 2 * idx + 2;
let top: t? = _arr[idx];
let left: t? = leftidx < _arr.count ? _arr[leftidx]: nil;
let right: t? = rightidx < _arr.count ? _arr[rightidx]: nil;
if let t = top
}else if let l = left
}else if let r = right }}
return false;
}/**
* 建立堆,依次調整 n/2 -> 0 元素
*/private func _create()
}/**
* 彈出乙個元素,移除頂部元素,然後令頂部元素等於最後乙個元素,最後調整頂部元素
* @return [t?] 返回頂部元素
*/func pop() -> t? else
}return first;
}/**
* 插入乙個元素,插入到尾部,依次調整該元素的頂部元素,直到無需調整或下標為0
* @param - t 插入的元素
*/func push(_ t: t)
if idx == 0
idx = int(ceilf(float(idx) / 2) - 1);}}
/*** 返回當前元素數量
* @return 返回堆內元素數量
*/func count() -> int
}
//常量
const bigheap =1;
const smallheap =2;
//建構函式
function
heap
(type, arr, comparefunction)
//陣列交換
heap.
_swap
=function
(i,j,arr)
//比較值
heap.prototype.
_compare
=function
(v1, v2)
else
else}}
else
else
else}}
}//調整堆的第i個結點
heap.prototype.
_adjustnode
=function
(i, arr)
let rightchildidx =
2* i +2;
let rightvalue =
null;if
(rightchildidx < arr.length)if(
!leftvalue &&
!rightvalue)
let exchangeidx =
null
;//左值存在並且大於根結點
if(leftvalue &&
this
._compare
(leftvalue, arr[i]))
else
}else
if(rightvalue &&
this
._compare
(rightvalue, leftvalue))if
(exchangeidx !=
null)}
//根據陣列建立堆
heap.prototype.
_createheap
=function
(arr)
//最後乙個非葉子結點
let lastnonleafidx = math.
floor
(len /2)
-1;//依次調整每個結點
for(
let index = lastnonleafidx; index >=
0; index--)}
//插入
heap.prototype.
insert
=function
(ele)}}
//刪除
heap.prototype.
remove
=function()
let value =
this
.arr[0]
;if(this
.arr.length >1)
else
return value;
}//是否為空
heap.prototype.
empty
=function()
陣列轉堆的複雜度
每次調整堆最少可能需要1次調整
實際上,需要少量調整的運算元遠遠大於需要多次調整的操作。
堆的插入:o(logn)
堆的刪除:o(logn)
演算法(4)資料結構 堆
實現資料結構 堆。堆一般使用陣列來表示,其中某個節點下標i的兩個子節點的下標為 2i 1 和 2i 2。堆是一棵完全二叉樹。堆有3種基本操作 建立,插入,刪除。這3種操作都需要通過 調整堆 的方式來實現。調整堆是指,對堆中的某個節點,若它的值和它所有子節點相比,不是最大 最小,那麼就需要將最大 最小...
資料結構與演算法 堆結構
1 本質 一顆特殊的樹。2 特性 3 分類 對於每乙個節點的值都大於等於子節點的值的情況,該堆被稱為大頂堆。對於每乙個節點的值都小於等於子節點的值的情況,該堆被稱為小頂堆。4 儲存方式 對於完全二叉樹而言,陣列儲存方式是最節省記憶體的。5 插入節點的時間複雜度 將節點插入到靠左的底層作為新的葉子節點...
資料結構與演算法 堆
堆 完全二叉樹,高度為o lgn 基本操作至多和樹的高度成正比,構建堆的時間複雜度是o n 堆是一顆完全二叉樹,假設有n個節點,樹高h log2 n 證明方法如下 1 假設根節點的高度為0,葉子節點高度為h,每層包含元素個數為2 x,x 從0 到h。2 構建堆的過程是自下而上,對於每層非葉子節點需要...