《大话数据结构》学习笔记 —— 03 线性表之循环链表(golang实现)


循环链表


前言

普通的单链表有一个明显的缺点,如果不从头结点出发,就无法访问到全部结点。


定义

将单链表中终端结点的指针由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表。


与单链表的区别

其实循环链表和单链表的主要区别在于循环的判断条件上,原来是判断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
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章