跳錶是平衡樹的一種替代的數據結構,可是和紅黑樹不相同的是,跳錶對於樹的平衡的實現是基於一種隨機化的算法的,這樣也就是說跳錶的插入和刪除的工做是比較簡單的。node
下面來研究一下跳錶的核心思想:算法
先從鏈表開始,若是是一個簡單的鏈表,那麼咱們知道在鏈表中查找一個元素I的話,須要將整個鏈表遍歷一次。數組
若是是說鏈表是排序的,而且節點中還存儲了指向前面第二個節點的指針的話,那麼在查找一個節點時,僅僅須要遍歷N/2個節點便可。數據結構
這基本上就是跳錶的核心思想,其實也是一種經過「空間來換取時間」的一個算法,經過在每一個節點中增長了向前的指針,從而提高查找的效率。dom
咱們定義:spa
若是一個基點存在k個向前的指針的話,那麼陳該節點是k層的節點。設計
一個跳錶的層MaxLevel義爲跳錶中全部節點中最大的層數。指針
下面給出一個完整的跳錶的圖示:code
那麼咱們該如何將該數據結構使用二進制存儲呢?經過上面的跳錶的很容易設計這樣的數據結構:orm
定義每一個節點類型:
//定義每一個節點類型: type nodeStructure struct { key int // key值 value int // value值 forward []*nodeStructure }
上面的每一個結構體對應着圖中的每一個節點,若是一個節點是一層的節點的話(如7,12等節點),那麼對應的forward將指向一個只含一個元素的數組,以此類推。
定義跳錶數據類型:
// 定義跳錶數據類型 type listStructure struct { level int /* Maximum level of the list (1 more than the number of levels in the list) */ header *nodeStructure /* pointer to header */ }
跳錶數據類型中包含了維護跳錶的必要信息,level代表跳錶的層數,header以下所示:
初始化的過程很簡單,僅僅是生成下圖中紅線區域內的部分,也就是跳錶的基礎結構:
//跳錶初始化 func newList() *listStructure { var l *listStructure var i int // 申請list類型大小的內存 l = &listStructure{} // 設置跳錶的層level,初始的層爲0層(數組從0開始) l.level = 0 // 生成header部分 l.header = newNodeOfLevel(MaxNumberOfLevels) // 將header的forward數組清空 for i = 0; i < MaxNumberOfLevels; i++ { l.header.forward[i] = nil } return l }
插入操做
因爲跳錶數據結構總體上是有序的,因此在插入時,須要首先查找到合適的位置,而後就是修改指針(和鏈表中操做相似),而後更新跳錶的level變量。
func insert(l *listStructure, key int, value int) bool { var k int // 使用了update數組 var update [MaxNumberOfLevels]*nodeStructure var p, q *nodeStructure p = l.header k = l.level fmt.Printf("list level: %v\n", k) for ; k >= 0; k-- { // 查找插入位置 q = p.forward[k] for q != nil && q.key < key { p = q q = p.forward[k] } // 設置update數組 update[k] = p } // 對於每一層進行遍歷 一直到最低層 // 這裏已經查找到了合適的位置,而且update數組已經 // 填充好了元素 貌似不插入重複元素 if q != nil && q.key == key { q.value = value return false } // 隨機生成一個層數 k = randomLevel() fmt.Printf("random Level: %v\n", k) if k > l.level { // 若是新生成的層數比跳錶的層數大的話 // 增長整個跳錶的層數 l.level++ k = l.level // 在update數組中將新添加的層指向l->header update[k] = l.header } // 生成層數個節點數目 q = newNodeOfLevel(k + 1) q.key = key q.value = value // 每層插入節點 for ; k >= 0; k-- { p = update[k] q.forward[k] = p.forward[k] p.forward[k] = q } // 若是程序運行到這裏,程序已經插入了該節點 return true }
刪除某個節點
和插入是相同的,首先查找須要刪除的節點,若是找到了該節點的話,那麼只須要更新指針域,若是跳錶的level須要更新的話,進行更新。
func delete(l *listStructure, key int) bool { var k, m int // 生成一個輔助數組update var update [MaxNumberOfLevels]*nodeStructure var p, q *nodeStructure p = l.header k = l.level m = l.level //指向該節點對應層的前驅節點 一直到最低層 for ; k >= 0; k-- { q = p.forward[k] for q != nil && q.key < key { p = q q = p.forward[k] } update[k] = p } // 若是找到了該節點,才進行刪除的動做 if q != nil && q.key == key { // 指針運算 for k = 0; k <= m && update[k].forward[k] == q; k++ { // 這裏可能修改l.header.forward數組的值的 p = update[k] p.forward[k] = q.forward[k] } // 若是刪除的是最大層的節點,那麼須要從新維護跳錶的 // 層數level for l.header.forward[m] == nil && m > 0 { m-- } l.level = m return true } else { return false } }
package main import ( "fmt" "math/rand" "time" ) //定義每一個節點類型: type nodeStructure struct { key int // key值 value int // value值 forward []*nodeStructure } // 定義跳錶數據類型 type listStructure struct { level int /* Maximum level of the list (1 more than the number of levels in the list) */ header *nodeStructure /* pointer to header */ } const ( MaxNumberOfLevels = 11 MaxLevel = 10 ) // newNodeOfLevel生成一個nodeStructure結構體,同時生成l個*nodeStructure數組指針 //#define newNodeOfLevel(l) (*nodeStructure)malloc(sizeof(struct nodeStructure)+(l)*sizeof(nodeStructure *)) func newNodeOfLevel(level int) *nodeStructure { nodearr := make([]*nodeStructure, level) //new([level]*node) return &nodeStructure{forward: nodearr} } //跳錶初始化 func newList() *listStructure { var l *listStructure var i int // 申請list類型大小的內存 l = &listStructure{} // 設置跳錶的層level,初始的層爲0層(數組從0開始) l.level = 0 // 生成header部分 l.header = newNodeOfLevel(MaxNumberOfLevels) // 將header的forward數組清空 for i = 0; i < MaxNumberOfLevels; i++ { l.header.forward[i] = nil } return l } func randomLevel() int { r := rand.New(rand.NewSource(time.Now().UnixNano())) return r.Intn(MaxLevel) } func insert(l *listStructure, key int, value int) bool { var k int // 使用了update數組 var update [MaxNumberOfLevels]*nodeStructure var p, q *nodeStructure p = l.header k = l.level for ; k >= 0; k-- { // 查找插入位置 q = p.forward[k] for q != nil && q.key < key { p = q q = p.forward[k] } // 設置update數組 update[k] = p } // 對於每一層進行遍歷 一直到最低層 // 這裏已經查找到了合適的位置,而且update數組已經 // 填充好了元素 貌似不插入重複元素 if q != nil && q.key == key { q.value = value return false } // 隨機生成一個層數 k = randomLevel() if k > l.level { // 若是新生成的層數比跳錶的層數大的話 // 增長整個跳錶的層數 l.level++ k = l.level // 在update數組中將新添加的層指向l->header update[k] = l.header } // 生成層數個節點數目 q = newNodeOfLevel(k + 1) q.key = key q.value = value // 每層插入節點 for ; k >= 0; k-- { p = update[k] q.forward[k] = p.forward[k] p.forward[k] = q } // 若是程序運行到這裏,程序已經插入了該節點 return true } func delete(l *listStructure, key int) bool { var k, m int // 生成一個輔助數組update var update [MaxNumberOfLevels]*nodeStructure var p, q *nodeStructure p = l.header k = l.level m = l.level //指向該節點對應層的前驅節點 一直到最低層 for ; k >= 0; k-- { q = p.forward[k] for q != nil && q.key < key { p = q q = p.forward[k] } update[k] = p } // 若是找到了該節點,才進行刪除的動做 if q != nil && q.key == key { // 指針運算 for k = 0; k <= m && update[k].forward[k] == q; k++ { // 這裏可能修改l.header.forward數組的值的 p = update[k] p.forward[k] = q.forward[k] } // 若是刪除的是最大層的節點,那麼須要從新維護跳錶的 // 層數level for l.header.forward[m] == nil && m > 0 { m-- } l.level = m return true } else { return false } } func search(l *listStructure, key int) int { var k int var p, q *nodeStructure p = l.header k = l.level //指向該節點對應層的前驅節點 一直到最低層 for ; k >= 0; k-- { q = p.forward[k] for q != nil && q.key < key { q = q.forward[k] } if q != nil && q.key == key { return q.value } } if q != nil && q.key == key { return q.value } else { return -1 } } func main() { l := newList() insert(l, 3, 30) insert(l, 6, 60) insert(l, 7, 70) insert(l, 9, 90) delete(l, 9) insert(l, 12, 120) insert(l, 17, 170) insert(l, 19, 190) fmt.Printf("skiplist:%v\n", search(l, 12)) fmt.Printf("skiplist:%v\n", search(l, 9)) }
程序輸出結果:
skiplist:120 skiplist:-1