惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
H
Help Net Security
博客园_首页
P
Privacy International News Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tenable Blog
Latest news
Latest news
D
Darknet – Hacking Tools, Hacker News & Cyber Security
爱范儿
爱范儿
Cyberwarzone
Cyberwarzone
P
Palo Alto Networks Blog
月光博客
月光博客
有赞技术团队
有赞技术团队
Know Your Adversary
Know Your Adversary
博客园 - 叶小钗
P
Proofpoint News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Schneier on Security
A
About on SuperTechFans
F
Full Disclosure
The Cloudflare Blog
T
The Exploit Database - CXSecurity.com
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Security Blog
Microsoft Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
N
News and Events Feed by Topic
www.infosecurity-magazine.com
www.infosecurity-magazine.com
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Webroot Blog
Webroot Blog
量子位
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
WordPress大学
WordPress大学
Last Week in AI
Last Week in AI
美团技术团队
Help Net Security
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
云风的 BLOG
云风的 BLOG
Y
Y Combinator Blog
博客园 - 司徒正美
N
Netflix TechBlog - Medium
S
Security @ Cisco Blogs
B
Blog
P
Privacy & Cybersecurity Law Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Hacker News - Newest:
Hacker News - Newest: "LLM"
V
Visual Studio Blog
NISL@THU
NISL@THU

博客园 - dribs

PD分离 基于GPT2训练构建医疗问诊机器人 物流行业信息咨询智能问答系统 day8 golang-chan-协程-定时器-锁-等待组 day7 golang GMP golang 自行实现一个base64加密 golang标准库log+第三方zerolog golang标准库序列化反序列化 json + 第三方msgpack golang 标准库 目录操作 golang-day1 进制 golang-标准库文件操作 golang-标准库时间time day6 golang-标准库(随时更新) golang--day5结构体+结构体排序+错误处理+结构体和接口实现面向对象的例子 golang-day4函数 ceph warn oldest client/flush tid ceph 扩容后healt-error k8s系列---pod手动驱逐 k8s系列---Chart(下)
golang面试题单向链表和双向链表
dribs · 2023-03-20 · via 博客园 - dribs

2023-03-20 15:58  dribs  阅读(84)  评论()    收藏  举报

甲流难受中,简单发一个链表

1.单项列表

package main

import (
	"fmt"
	"strconv"
)

type Node struct {
	value int
	next  *Node
}
type Linklist struct {
	len  int
	head *Node
	tail *Node
}

//构造函数linklist
func NewLinklist() *Linklist {
	return &Linklist{}
}

func (l *Linklist) Append(value int) *Linklist {
	//1.构建实例创建元素,next悬空为nil
	node := &Node{value: value}
	//node.next = nil //默认是nil
	//2.老尾巴指向node
	//2.1 如果tail为空 即一个元素也没有,tail此时为nil,nil是无法next的,head和tail都是该node.len==0,l.head=nil
	if l.tail == nil {
		l.head = node
	} else {
		//如果至少有一个元素,尾巴就可以指到下一个节点
		l.tail.next = node
	}
	//3.更新尾巴
	l.tail = node
	l.len++
	return l
}

//遍历链表取出各个元素
func (l *Linklist) Iternodes() {
	//链表头节点
	p := l.head
	for p != nil {
		fmt.Println(p)
		p = p.next
	}
}

func (n *Node) String() string {
	var s string
	if n.next == nil {
		s = "null"
	} else {
		s = strconv.Itoa(n.next.value)
	}
	return fmt.Sprintf("%d --> %s", n.value, s)
}
func main() {
	linklist := NewLinklist()
	//fmt.Println(linklist)
	l := linklist.Append(1111).Append(22)
	fmt.Println(l)

	l.Iternodes()
}

2.双向链表

package main

import (
	"errors"
	"fmt"
	"strconv"
)

type Node struct {
	item int
	next *Node //nil
	prev *Node //nil
}

type DoubleLinkList struct {
	len  int
	head *Node
	tail *Node
}

func NewDoubleLinkList() *DoubleLinkList {
	return &DoubleLinkList{}
}

func (n *Node) String() string {
	var s1, s2 string
	if n.next == nil {
		s1 = "null"
	} else {
		s1 = strconv.Itoa(n.next.item)
	}
	if n.prev == nil {
		s2 = "null"
	} else {
		s2 = strconv.Itoa(n.prev.item)
	}
	return fmt.Sprintf("%s<--%d--->%s", s2, n.item, s1)
}

//遍历链表取出各个元素
func (l *DoubleLinkList) Iternodes() []*Node {
	//向后遍历 找链表头节点
	p := l.head
	//复用这个for循环给insert的方法用
	nodelist := make([]*Node, 0, l.len)
	for p != nil {
		nodelist = append(nodelist, p)
		//insert方法的时候暂时注释掉该打印便于查看
		//fmt.Println(p)
		p = p.next
	}
	return nodelist
	//向后遍历 找链表尾节点
	//p = l.tail
	//for p != nil {
	//	fmt.Println(p)
	//	p = p.prev
	//}
}

//追加元素
func (l *DoubleLinkList) Append(value int) *DoubleLinkList {
	//1、构造node
	node := new(Node)
	node.item = value
	//node.next=nil  初始化默认为nil
	//node.prev=nil  初始化默认为nil

	//2、老尾巴指向node
	if l.tail == nil {
		//2.1一个元素也没有,头尾都是当前node
		l.head = node
		//l.tail = node //至少有一个的时候也会挪尾巴,抽出来
		//node.prev = nil  //l.tail,prev ==nil  //默认为nil 一个没有追加了一个,此时prev next都还是nil
		//node.next = nil  //l.tail.next ==nil  //默认不写为nil
	} else {
		//至少有一个的时候,head头不动,前一个的next指下一个,下一个的prev指前一个尾巴、其他不动
		//l.head  //尾部追加的时候头不动
		//l.tail.prev //不动
		l.tail.next = node
		node.prev = l.tail
		//node.next = nil   //默认为空
		//l.tail = node  //在没元素的时候追加一个也会挪尾巴,抽出来
	}
	//更新尾巴
	l.tail = node
	l.len++
	return l
}
func (l *DoubleLinkList) Pop() error {
	//1、没有任何元素的时候弹出错误,没有元素 即l.len==0 或 l.tail == nil 或 l.head==nil
	if l.len == 0 {
		return errors.New("empty")
	} else if l.head == l.tail {
		//只有一个元素,l.head==0xc000004090 l.tail==0xc000004090,所以上面在没有元素的时候 不推荐l.head==l.tail判断
		//上面已经把0个元素过滤掉了,所以这里l.head==l.tail做判断不会出现0个元素的情况
		//移除节点后 没有了节点 所以head和tail都是nil
		l.head = nil
		l.tail = nil
	} else {
		//不止一个元素的时候弹出
		//1、断开手拉手,即前一个(l.tail.prev)的next = nil
		//2、更新尾巴 即 l.tail = 前一个节点
		//其他不必要的手拉手 不管 即 l.tail.prev =nil l.tail.next=nil
		//前面的节点不动,更新len
		l.tail.prev.next = nil
		l.tail = l.tail.prev

	}
	l.len--
	return nil
}

func (l *DoubleLinkList) Insert(index, value int) error {
	//如果索引为负数
	if index < 0 {
		return errors.New("invalid position")
	}
	//index>0
	//定义当前节点
	var current *Node
	//Iternodes至少有一个元素的时候
	for i, node := range l.Iternodes() {
		//找到当前节点
		if index == i {
			current = node
			break
		}
		//Iternodes至少有一个元素的时候,如果遍历完Iternodes还没有和insret的索引匹配证明索引超界,那也追加
		//如果Iternodes 没有元素的时候 也会执行尾部追加 append会写两次,所以此处注释掉挪外面
		//else {
		//	l.Append(value)
		//}
	}
	//如果没找到,可能超界;也可能这个时候for循环也没走即Iternodes里没有任何元素,就尾部追加
	if current == nil {
		l.Append(value)
		return nil
	}
	//找到了插入点,一定不是尾部追加
	//分两种 1是开头插入 2是中间插入 都不会动他的尾巴
	node := new(Node)
	node.item = value
	//开头插入的条件 index=0 或current.prev = nil 或 l.head = nil
	if index == 0 {
		//当前节点的prev指到新增的节点
		current.prev = node
		//头 改成新增节点
		l.head = node
		//新头的下一个指到当前节点
		l.head.next = current //node.next = current
	} else {
		node.prev = current.prev
		node.prev.next = node
		current.prev = node
		current.prev.next = current //node.next = current

	}
	l.len++
	fmt.Println(current)
	return nil
}

func main() {
	dll := NewDoubleLinkList()
	l := dll.Append(100).Append(200).Append(300)
	fmt.Println(l)
	l.Iternodes()
	fmt.Println("=====Pop======")
	p := l.Pop()
	fmt.Println(p)
	l.Iternodes()
	fmt.Println("------insert------")
	l.Insert(1, 50)
	fmt.Println(l.Iternodes())
}