GO数据结构与算法
LinkedList
SingleLinkedList
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
单链表的特点:
- 单链表不要求逻辑上相邻的两个元素在物理位置上也相邻,因此不需要连续的存储空间。
- 单链表是非随机的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。
//以下是使用GO语言实现单向列表算法的代码
package main
import (
"fmt"
)
// HeroNode 定义HeroNode , 每个HeroNode 对象就是一个节点
type HeroNode struct {
no int
name string
nickname string
next *HeroNode
}
// NewHeroNode 构造 // go语言没有自带的构造函数 // 返回指针,以方便调用
func NewHeroNode(no int, name string, nickname string) *HeroNode {
return &HeroNode{
no,
name,
nickname,
nil,
}
}
//重写String方法,以便输出时依照格式
func (node *HeroNode) String() string {
return fmt.Sprintf("HeroNode [no=%d\t\tname=%s\tnickname=%s]", node.no, node.name, node.nickname)
}
// SingleLinkedList 定义SingleLinkedList 管理
type SingleLinkedList struct {
head *HeroNode //定义一个头指针
}
// add
func (s *SingleLinkedList) add(heroNode *HeroNode) {
temp := s.head //临时指针指向链表头部
for temp.next != nil { //临时指针没有指向链表尾部时
temp = temp.next //后移指针
}
temp.next = heroNode
}
// addByOrder 按排名添加
func (s *SingleLinkedList) addByOrder(heroNode *HeroNode) {
temp := s.head
flag := false
for {
if temp.next == nil {
break // temp在末尾
}
if temp.next.no > heroNode.no {
break //位置找到在temp后面插入
} else if temp.next.no == heroNode.no {
flag = true // 编号存在
break//退出
}
temp = temp.next//后移
}
if flag {
fmt.Printf("准备插入的编号 %d 已经存在了,不能加入\n", heroNode.no)
} else {
heroNode.next = temp.next
temp.next = heroNode
}
}
// reverseStackPrint,运用stack特性 //由于go语言没有stack的官方包,我们可以通过切片模拟 //或者导入外部包,可从github上找到
func (s *SingleLinkedList) reverseStackPrint() {
if s.head.next == nil {
fmt.Println("空链表")
return
}
stack := make([]*HeroNode, 0)
cur := s.head.next
//入栈
for cur != nil {
stack = append(stack, cur)
cur = cur.next
}
for len(stack) > 0 {
top := stack[len(stack)-1] //栈顶
stack = stack[:len(stack)-1]
fmt.Println(top)
}
}
// update 修改节点的信息, 根据no编号来修改
func (s *SingleLinkedList) update(newHeroNode *HeroNode) {
if s.head.next == nil {
fmt.Println("链表为空")
return
}
temp := s.head.next
flag := false
for temp != nil {
if temp.no == newHeroNode.no {
flag = true
break
}
temp = temp.next
}
if flag {
temp.name = newHeroNode.name
temp.nickname = newHeroNode.nickname
} else {
fmt.Println("没有找到节点")
}
}
// del del单向列表信息的功能
func (s *SingleLinkedList) del(no int) {
temp := s.head
flag := false
for {
if temp.next == nil {
break //链表最后
}
if temp.next.no == no {
flag = true//改变flag
break
}
temp = temp.next
}
if flag {
temp.next = temp.next.next
} else {
fmt.Printf("没找到要删除的节点%d\n", no)
}
}
// getLength 获取链表节点个数
func (s *SingleLinkedList) getLength() int {
if s.head.next == nil {
return 0
}
var length = 0
cur := s.head.next
for cur != nil {
length++
cur = cur.next
}
return length
}
// findLastIndexNode 找倒数的index
func (s *SingleLinkedList) findLastIndexNode(index int) *HeroNode {
//链表空返回nil
if s.head.next == nil {
return nil
}
size := s.getLength()
if index <= 0 || index > size {
return nil
}
cur := s.head.next
for i := 0; i < size-index; i++ {
cur = cur.next
}
return cur
}
// reverseList 链表倒置
//1. next = cur.next: 我们先暂时保存当前节点 cur 的下一个节点,
// 因为在修改 cur.next 指针之后,会失去对下一个节点的引用。
//2. cur.next = reverseHead.next: 将当前节点 cur 的下一个节点指向新链表的最前端。
// 也就是将 cur 的 next 指针指向 reverseHead.next,这样当前节点就成为了新链表的第一个节点。
//3. reverseHead.next = cur: 将当前节点 cur 连接到新链表上。
// 我们将 cur 插入到 reverseHead 的后面,使其成为新链表的头部。
//4. cur = next: 将 cur 后移,指向原链表中保存的下一个节点。
// 这样我们可以继续处理下一个节点,重复以上步骤,直到链表全部反转完成。
func (s *SingleLinkedList) reverseList() {
if s.head.next == nil || s.head.next.next == nil {
return
}
cur := s.head.next
var next *HeroNode //指向cur当前节点的下一个节点
reverseHead := NewHeroNode(0, "", "") //新链表
for cur != nil {
next = cur.next //保存当前节点下一个节点
cur.next = reverseHead.next //cur下一个节点指向新链表最前端
reverseHead.next = cur //cur链接在新链表上
cur = next //cur后移
}
//head.next指向reverseHead.next从而反转
s.head.next = reverseHead.next
}
// list 显示链表[遍历]
func (s *SingleLinkedList) list() {
if s.head.next == nil {
fmt.Println("链表为空")
return
}
temp := s.head.next
for temp != nil {
fmt.Println(temp)
temp = temp.next
}
}
func main() {
// 初始化一个头节点
head := &HeroNode{}
singleLinkedList := &SingleLinkedList{
head: head,
}
hero1 := NewHeroNode(1, "钟离", "盐王")
hero2 := NewHeroNode(2, "windy", "卖唱的")
hero3 := NewHeroNode(3, "雷军", "不会做饭的")
hero4 := NewHeroNode(4, "小狗", "小猫")
singleLinkedList.addByOrder(hero1)
singleLinkedList.addByOrder(hero3)
singleLinkedList.addByOrder(hero2)
singleLinkedList.addByOrder(hero4)
singleLinkedList.list()
fmt.Println("--------------------------update修改后--------------------------")
heroupdate := NewHeroNode(4, "小草神", "你好")
singleLinkedList.update(heroupdate)
singleLinkedList.list()
fmt.Println("--------------------------del删除后------------------------------")
singleLinkedList.del(2)
singleLinkedList.list()
fmt.Println("--------------------------节点长度--------------------······------")
singleLinkedList.addByOrder(NewHeroNode(2, "温迪", "卖唱的"))
singleLinkedList.list()
num := singleLinkedList.getLength()
fmt.Println("链表节点个数", num)
fmt.Println("------------------------倒序索引实例-------------------------------")
fmt.Println(singleLinkedList.findLastIndexNode(1))
fmt.Println(singleLinkedList.findLastIndexNode(2))
fmt.Println(singleLinkedList.findLastIndexNode(3))
fmt.Println(singleLinkedList.findLastIndexNode(4))
fmt.Println("------------------------单链表的反转-------------------------------")
singleLinkedList.reverseList()
singleLinkedList.list()
fmt.Println("------------------------栈的反转-----------------------------------")
singleLinkedList.reverseStackPrint()
}