循环链表
前言
普通的单链表有一个明显的缺点,如果不从头结点出发,就无法访问到全部结点。
定义
将单链表中终端结点的指针由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表。
与单链表的区别
其实循环链表和单链表的主要区别在于循环的判断条件上,原来是判断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
}