實現資料結構:堆。
堆一般使用陣列來表示,其中某個節點下標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];
letleft: t? = leftidx < _arr.count ? _arr[leftidx]: nil;
letright: t? = rightidx < _arr.count ? _arr[rightidx]: nil;
iflet t = top
}else
iflet l = left
}else
iflet 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)elseelse
}}elseelseelse}}
}//調整堆的第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 構建堆的過程是自下而上,對於每層非葉子節點需要...