1. 链表
它的存储特点为:可以用任意一组存储单元来存储单链表中的数据元素(存储单元可以是不连续的),而且,除了存储每个数据元素ai外,还必须存储指示其直接后继元素的信息。这两部分信息组成的数据元素ai的存储映像称为结点。N个结点链在一块被称为链表,当结点只包含其后继结点信息的链表就被称为单链表,而链表的第一个结点通常被称为头结点,对于单链表,又可以将其分为有头结点的单链表和无头结点的单链表.当节点既包含其后继节点信息,也包含前驱节点信息的链表被称为双链表。
2. 单链表
2.1 带头结点的单链表
在单链表的开始节点之前附设一个类型相同的节点,称为头结点。头结点的数据域可以不存储任何信息(也可以存放如线性表的长度等附加信息),头结点的指针域存储指向开始节点的指针(即第一个元素节点的存储位置):
优点:
-
对于带头结点的链表,当在链表的任何结点之前插入新结点或删除链表中任何结点时,所要做的都是修改前一个结点的指针域,因为任何结点都有前驱结点。若链表没有头结点,则首元素结点没有前驱结点,在其前面插入结点或删除该结点时操作会复杂些,需要进行特殊的处理。
-
对于带头结点的链表,链表的头指针是指向头结点的非空指针,因此,对空链表与非空链表的处理是一样的。
2.2 不带头结点的单链表
单链表的开始节点之前没有附设一个类型相同的空节点。直接从开始节点开始,随着在单链表的开始节点直接插入新的节点,头结点会随时变化(此处的头结点是指谁是第一个节点即为头结点)
3. 双链表
对于一个节点,有些和单链表一样有存储数据的data
,指向后方的next
(指针)。它拥有单链表的所有操作和内容。但是他还有一个前驱节点pre
(指针)
对于双向量表,给定任意一个节点,都可以遍历整个链表的数据。相比于单链表,进行数据查找快,但是空间开销是单链表的两倍,相当于是空间换时间。需要根据具体的实际情况进行选择
4. go语言与链表
4.1 创建单链表
package main
import "fmt"
//链表定义
type LNode struct {
Data interface{}
Next *LNode
}
func main() {
head := &LNode{} // 定义头结点
cur := head // 移动变量
for i := 1; i < 10; i++ { // 创建长度为10的链表
cur.Next = &LNode{} // 指向链表的后驱节点
cur.Next.Data = i // 指向后驱节点的数据域
cur = cur.Next // 指针向后移动一位
}
printNodeList(head)
}
func printNodeList(head *LNode) {
for cur := head.Next; cur != nil; cur = cur.Next {
fmt.Printf("%v ", cur.Data)
}
}
4.2 创建双向链表
package main
import (
"fmt"
"strconv"
"sync"
)
type Data struct {
Name string `json:"name"`
Age int `json:"age"`
}
type Node struct {
Pre *Node
Next *Node
Data Data
}
type NodeList struct {
mutex *sync.Mutex
Head *Node
Tail *Node
Size uint
}
type NodeInterface interface {
Init()
Append(node *Node)
InsertAfterNode(node *Node, data Data) error
InsertIndex(index uint, data Data) error
DelNode(node *Node)
PrintNodeList()
IsEmpty() bool
GetNodeListLen() uint
Exist(node *Node) bool
InsertHead(data Data)
}
func Factory() NodeInterface {
return &NodeList{}
}
// Init,链表的初始化
func (this *NodeList) Init() {
this.Head = nil
this.Tail = nil
this.Size = 0
this.mutex = new(sync.Mutex)
}
// Append,在链表尾部插入节点
func (this *NodeList) Append(node *Node) {
this.mutex.Lock()
defer this.mutex.Unlock()
if this.Size == 0 {
this.Head = node
this.Tail = node
this.Size = 1
return
}
nodePre := this.Tail
this.Tail.Next = node
node.Pre = nodePre
this.Tail = node
this.Size++
}
// Exit, 判断节点是否在当前链表中存在
func (this *NodeList) Exist(node *Node) bool {
var p = this.Head
for p != nil {
if p == node {
return true
}
p = p.Next
}
return false
}
// InsertAfterNode,在指定节点后插入数据
func (this *NodeList) InsertAfterNode(node *Node, data Data) error {
// 如果当前节点存在插入数据,不存在报错
if !this.Exist(node) {
return fmt.Errorf("the current node is not exist")
}
newNode := &Node{
Data: data,
Next: nil,
}
if node.Next == nil {
this.Append(newNode)
} else if node.Pre == nil {
newNode.Next = node.Next
newNode.Pre = node
node.Next = newNode
this.Size++
} else {
newNode.Next = node.Next
newNode.Pre = node
node.Next = newNode
this.Size++
}
return nil
}
// InsertIndex,在指定下标处插入数据
func (this *NodeList) InsertIndex(index uint, data Data) error {
// 判断下标值是否合法
if index > this.Size {
return fmt.Errorf("the index is more than the nodeList subscript")
}
// index=0,即在链表头部插入数据
if index == 0 {
this.InsertHead(data)
return nil
}
// 遍历到指定下标对应的节点
var p = this.Head
for i := 0; i < int(index); i++ {
p = p.Next
}
if err := this.InsertAfterNode(p, data); err != nil {
return err
}
return nil
}
// InsertHead,在链表头部插入数据
func (this *NodeList) InsertHead(data Data) {
newNode := &Node{
Data: data,
Next: this.Head,
}
this.Head.Pre = newNode
this.Head = newNode
if this.Size == 0 {
this.Tail = newNode
}
this.Size++
}
// DelNode,删除指定节点
func (this *NodeList) DelNode(node *Node) {
// 判断是否是头节点
if this.Head == node {
this.Head = this.Head.Next
}
// 判断是否是尾节点
if this.Tail == node {
p := this.Head
for p.Next != node {
p = p.Next
}
p.Next = nil
p.Next.Pre = nil
}
// 如果是中间节点
p := this.Head
for p.Next != node {
p = p.Next
}
p.Next = node.Next
node.Next.Pre = node.Pre
this.Size--
}
// GetNodeListLen,获取链表长度
func (this *NodeList) GetNodeListLen() uint {
return this.Size
}
// IsEmpty,判断链表是否为空
func (this *NodeList) IsEmpty() bool {
return this.Size == 0
}
// PrintNodeList, 打印链表信息
func (this *NodeList) PrintNodeList() {
fmt.Println("==============打印链表信息==============")
if this.IsEmpty() {
fmt.Println("当前链表为空")
}
fmt.Printf("链表长度 : %v\n", this.GetNodeListLen())
p := this.Head
//for p.Next != nil {
for {
fmt.Printf("the node : %v\n", p.Data)
if p.Next == nil {
break
} else {
p = p.Next
}
}
fmt.Println("==============打印链表信息==============")
}
func main() {
factory := Factory()
factory.Init()
for i := 0; i <= 10; i++ {
factory.Append(&Node{
Data: Data{
Name: "test_" + strconv.Itoa(i),
Age: i,
},
Next: nil,
})
}
fmt.Println("=============初始化的链表=============")
factory.PrintNodeList()
fmt.Println("=============初始化的链表=============")
fmt.Println("")
fmt.Println("")
fmt.Println("")
fmt.Println("=============在指定节点后插入数据=============")
data := Data{
Name: "zhangyang",
Age: 28,
}
node := factory.(*NodeList).Head
for i := 0; i < 6; i++ {
node = node.Next
}
if err := factory.InsertAfterNode(node, data); err != nil {
panic(err)
}
if err := factory.InsertAfterNode(node.Next, data); err != nil {
panic(err)
}
factory.PrintNodeList()
fmt.Println("=============在指定节点后插入数据=============")
fmt.Println("")
fmt.Println("")
fmt.Println("")
fmt.Println("=============在指定下标插入数据=============")
data = Data{
Name: "taoyingying",
Age: 25,
}
if err := factory.InsertIndex(8, data); err != nil {
panic(err)
}
factory.PrintNodeList()
fmt.Println("=============在指定下标插入数据=============")
fmt.Println("")
fmt.Println("")
fmt.Println("")
fmt.Println("=============删除指定节点=============")
node = factory.(*NodeList).Head
for i := 0; i < 7; i++ {
node = node.Next
}
factory.DelNode(node)
factory.PrintNodeList()
fmt.Println("=============删除指定节点=============")
}