skiplist(跳錶)算法實現

跳錶是平衡樹的一種替代的數據結構,可是和紅黑樹不相同的是,跳錶對於樹的平衡的實現是基於一種隨機化的算法的,這樣也就是說跳錶的插入和刪除的工做是比較簡單的。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

	}
}

skiplist完整代碼

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
相關文章
相關標籤/搜索