循環鏈表
前言
普通的單鏈表有一個明顯的缺點,如果不從頭結點出發,就無法訪問到全部結點。
定義
將單鏈表中終端結點的指針由空指針改爲指向頭結點,就使整個單鏈表形成一個環,這種頭尾相接的單鏈表稱爲單循環鏈表,簡稱循環鏈表。
與單鏈表的區別
其實循環鏈表和單鏈表的主要區別在於循環的判斷條件上,原來是判斷p->next是否爲空,現在是判斷p->next是否等於頭結點。
代碼實現
package CricleLinkling
import "fmt"
// 循環表結點
type CricleLinkNode struct {
value interface{}
pNext *CricleLinkNode
}
// 構造結點
func NewCricleLinkNode(data interface{}) *CricleLinkNode {
return &CricleLinkNode{
value: data,
pNext: nil,
}
}
// 返回數據
func (node *CricleLinkNode) Value() interface{} {
return node.value
}
// 返回下一個結點
func (node *CricleLinkNode) PNext() *CricleLinkNode {
return node.pNext
}
// 定義循環鏈表接口
type CricleLink interface {
// 返回第一個數據結點
GetFirstNode() *CricleLinkNode
// 插入結點(頭插法)
InsertNodeFront(node *CricleLinkNode)
// 插入結點(尾插法)
InsertNodeBack(node *CricleLinkNode)
// 插入某結點前
InsertNodeValueFront(dest interface{}, node *CricleLinkNode) bool
// 插入某結點後
InsertNodeValueBack(dest interface{}, node *CricleLinkNode) bool
// 獲取指定索引上的結點
GetNodeAtIndex(index int) *CricleLinkNode
// 刪除結點
DeleteNode(dest *CricleLinkNode) bool
// 刪除指定索引上的結點
DeleteAtIndex(index int) bool
// 返回字符串
String() string
}
// 循環鏈表
type CricleLinkList struct {
// 頭指針
head *CricleLinkNode
// 長度
length int
}
// 初始化循環鏈表
func NewCricleLinkList() *CricleLinkList {
// 初始化頭結點
head := NewCricleLinkNode(nil)
return &CricleLinkList{
head: head,
length: 0,
}
}
// 獲取第一個數據結點
func (list *CricleLinkList) GetFirstNode() *CricleLinkNode {
return list.head.pNext
}
// 獲取指定索引上的結點
func (list *CricleLinkList) GetNodeAtIndex(index int) *CricleLinkNode {
// 索引越界
if index > list.length-1 || index < 0 {
return nil
}
// 備份頭結點
bak := list.head
// 向後循環
for index > -1 {
bak = bak.pNext
index--
}
return bak
}
// 頭部插入
func (list *CricleLinkList) InsertNodeFront(node *CricleLinkNode) {
// 備份頭結點
bak := list.head
// 空鏈表
if bak.pNext == nil {
// 新結點賦值爲第一個數據結點
bak.pNext = node
// 新結點的指針指向頭結點
node.pNext = bak
list.length++
return
}
// 新結點的指針,指向原來的第一個數據結點
node.pNext = bak.pNext
// 頭結點指向新結點
bak.pNext = node
list.length++
return
}
// 尾部插入
func (list *CricleLinkList) InsertNodeBack(node *CricleLinkNode) {
// 備份頭結點
bak := list.head
bak2 := list.head
// 空鏈表
if bak.pNext == nil {
// 新結點賦值爲第一個數據結點
bak.pNext = node
// 新結點的指針指向頭結點
node.pNext = bak
list.length++
return
}
// 循環到鏈表末尾
for bak.pNext != list.head {
bak = bak.pNext
}
// 終端結點的指針指向新結點
bak.pNext = node
// 新結點的指針指向頭結點
node.pNext = bak2
list.length++
return
}
// 插入某結點前
func (list *CricleLinkList) InsertNodeValueFront(dest interface{}, node *CricleLinkNode) bool {
// 備份頭結點
bak := list.head
// 循環到末尾,直至找到目標結點
for bak.pNext != bak && bak.pNext.value != dest {
bak = bak.pNext
}
// 找到
if bak.pNext.value == dest {
// 目標結點的上一個數據結點的指針,賦值給新結點的指針
node.pNext = bak.pNext
// 目標結點的上一個數據結點的指針,指向新結點
bak.pNext = node
list.length++
return true
}
return false
}
// 插入某結點後
func (list *CricleLinkList) InsertNodeValueBack(dest interface{}, node *CricleLinkNode) bool {
// 備份頭結點
bak := list.head
// 循環到末尾,直至找到目標結點
for bak.pNext != bak && bak.pNext.value != dest {
bak = bak.pNext
}
// 找到
if bak.pNext.value == dest {
// 目標結點的指針賦值給新結點的指針
node.pNext = bak.pNext.pNext
// 目標結點的指針指向新結點
bak.pNext.pNext = node
list.length++
return true
}
return false
}
// 刪除結點
func (list *CricleLinkList) DeleteNode(dest *CricleLinkNode) bool {
// 備份頭結點
bak := list.head
// 結點爲空
if dest == nil {
return false
}
// 循環到末尾,直至找到目標結點
for bak.pNext != bak && bak.pNext != dest {
bak = bak.pNext
}
// 找到
if bak.pNext == dest {
// 目前結點的指針賦值給目標結點的上一個數據結點的指針
bak.pNext = bak.pNext.pNext
list.length--
return true
}
return false
}
// 刪除指定索引上的結點
func (list *CricleLinkList) DeleteAtIndex(index int) bool {
// 索引越界
if index > list.length-1 || index < 0 {
return false
}
// 備份頭結點
bak := list.head
// 向後循環,找到前一個結點
for index > 0 {
bak = bak.pNext
index--
}
// 目前結點的指針賦值給目標結點的上一個數據結點的指針
bak.pNext = bak.pNext.pNext
list.length--
return true
}
// 返回字符串
func (list *CricleLinkList) String() string {
var listString string
// 頭結點
p := list.head
// 循環輸出
for p.pNext != list.head {
listString += fmt.Sprintf("%v-->", p.pNext.value)
p = p.pNext
}
listString += fmt.Sprintf("nil")
return listString
}