Golang leetcode707 设计链表 (链表大成)

文章目录

  • [设计链表 Leetcode707](#设计链表 Leetcode707)

设计链表 Leetcode707

题目要求我们通过实现几个方法来完成对链表的各个操作

由于在go语言中都为值传递,(注意这里与值类型、引用类型的而区别),所以即使我们直接在方法中传入指针,但是我们在方法里是不能直接修改指针所改的地址,其在方法中只会复制一份副本进行操作,而不会影响到原变量。

所以我们这里可以设置一个结构体,在mylinkedlist中在定义链表节点进行解决。
关于值传递的注意事项

这里放一个经典的愚蠢案例以作警戒,妄想通过副本直接影响原链表

我是猪

go 复制代码
func (this *MyLinkedList) AddAtTail(val int) {
	Node := this.Head
	if Node == nil {
		Node = &ListNode{Val: val}
		//this.Head = Node
		return
	}
	for Node.Next != nil {
		Node = Node.Next
	}
	Node.Next = &ListNode{Val: val}
}

不使用头节点

go 复制代码
// ListNode 定义链表结构
type ListNode struct {
	Val  int
	Next *ListNode
}

//正常建立,不涉及头节点
// MyLinkedList 为了方便操作链表建立的结构体
type MyLinkedList struct {
	size int
	Head *ListNode
}

// Constructor 初始化链表对象 √
func Constructor() MyLinkedList {
	return MyLinkedList{}
}

// Get 获取第index个节点的数据 √
func (this *MyLinkedList) Get(index int) int {
	if index+1 > this.size {
		return -1
	}

	Node := this.Head

	for ; index > 0; index-- {
		Node = Node.Next
	}

	return Node.Val
}

// AddAtHead 将数据为val的节点添加到第一位 √
func (this *MyLinkedList) AddAtHead(val int) {
	Node := &ListNode{Val: val, Next: this.Head}
	this.Head = Node
	this.size++
}

// AddAtTail 将数据为val的节点添加到最后一位 √
func (this *MyLinkedList) AddAtTail(val int) {
	this.size++
	if this.Head == nil {
		this.Head = &ListNode{Val: val}
		return
	}
	Node := this.Head
	for Node.Next != nil {
		Node = Node.Next
	}
	Node.Next = &ListNode{Val: val}
}

// AddAtIndex 将数据为val的节点插入到第index个节点之前;若链表长度为index,则放置到最后一位;若超过链表长度不做修改 √
func (this *MyLinkedList) AddAtIndex(index int, val int) {
	if this.size == index {
		this.AddAtTail(val)
		return
	}
	if this.size < index {
		return
	}
	//有第index节点
	//如果index=0,则需要改动首结点,直接待用addAtHead
	if index == 0 {
		this.AddAtHead(val)
		return
	}

	cur := this.Head
	Node := cur

	//0 1 2 3	;index=2
	for ; index > 1; index-- {
		Node = Node.Next
	}
	Node.Next = &ListNode{Val: val, Next: Node.Next}
	this.Head = cur
	this.size++
}

// DeleteAtIndex 删除第index个节点
func (this *MyLinkedList) DeleteAtIndex(index int) {
	if index+1 > this.size {
		return
	}

	// 0 1 2 3	;index=0
	//如果index=0,依旧需要修改头节点
	if index == 0 {
		this.Head = this.Head.Next
		this.size--
		return
	}

	Node := this.Head
	cur := Node

	0 1 2 3	;index=3,删除最后一个,只需要将最后.next=nil
	//if index+1 == this.size {
	//	for ; index > 1; index-- {
	//		cur = cur.Next
	//	}
	//	cur.Next = nil
	//	this.Head = Node
	//	this.size--
	//	return
	//}
	//
	0 1 2 3	;index=2
	//for ; index > 1; index-- {
	//	cur = cur.Next
	//}
	//cur.Next = cur.Next.Next
	//this.Head = Node
	//this.size--

	for ; index > 1; index-- {
		cur = cur.Next
	}
	if index+1 == this.size {
		cur.Next = nil
		this.size--
		return
	}
	cur.Next = cur.Next.Next
	this.Head = Node
	this.size--
}

使用头节点 推荐**

首先性能足够优秀,而且代码简洁还方便

go 复制代码
//本次目标时建立具有 头节点 的链表(虚拟头节点,但实际就是有头节点)
//链表结构:H* 0 1 2 3
//优势,在对头节点后的节点进行操作会方便

type MyLinkedList struct {
	Size      int
	DummyHead *ListNode
}

// Constructor 使用虚拟头节点时,很关键的一步在在初始化我们的mylinkedlist,我们需要直接对dummyhead分配内存空间,防止后续对首个节点进行操作时出现问题
func Constructor() MyLinkedList {
	return MyLinkedList{DummyHead: &ListNode{}}
}

func (this *MyLinkedList) Get(index int) int {
	//*h 0 1 2 3	;0
	if this.Size <= index {
		return -1
	}

	DummyHead := this.DummyHead
	cur := DummyHead

	for ; index >= 0; index-- {
		cur = cur.Next
	}

	return cur.Val
}

func (this *MyLinkedList) AddAtHead(val int) {

	//if this.Size == 0 {
	//	this.Head = &ListNode{Next: &ListNode{Val: val}}
	//	this.Size++
	//} else {
	//	this.Head.Next = &ListNode{Val: val, Next: this.Head.Next}
	//	this.Size++
	//}

	//newNode := &ListNode{Val: val} // 创建新节点
	//newNode.Next = this.Head.Next  // 新节点指向当前头节点
	//this.Head.Next = newNode       // 新节点变为头节点
	//this.Size++                    // 链表大小增加1

	//上面第一块没想明白,逻辑有问题;第二部分进行整合,本质一样
	this.DummyHead.Next = &ListNode{Val: val, Next: this.DummyHead.Next}
	this.Size++
}

func (this *MyLinkedList) AddAtTail(val int) {
	if this.Size == 0 {
		this.AddAtHead(val)
		return
	}
	DummyHead := this.DummyHead
	cur := DummyHead
	//h* 0 1 2 3 4	;
	for cur.Next != nil {
		cur = cur.Next
	}
	cur.Next = &ListNode{Val: val}
	this.DummyHead = DummyHead
	this.Size++
}

func (this *MyLinkedList) AddAtIndex(index int, val int) {
	//如果index=链表长度,插入到末尾
	if this.Size == index {
		this.AddAtTail(val)
		return
	}
	//如果index>链表长度,什么都不做

	//<长度,插入到index节点前
	//h* 0 1 2 3 4	;2
	if this.Size > index {
		DummyHead := this.DummyHead
		cur := DummyHead

		for ; index > 0; index-- {
			cur = cur.Next
		}
		cur.Next = &ListNode{Val: val, Next: cur.Next}
		this.DummyHead = DummyHead
		this.Size++
	}

}

func (this *MyLinkedList) DeleteAtIndex(index int) {
	//h* 0 1 2 3 4	;0

	if this.Size > index {
		DummyHead := this.DummyHead
		cur := DummyHead

		for ; index > 0; index-- {
			cur = cur.Next
		}
		cur.Next = cur.Next.Next
		this.DummyHead = DummyHead
		this.Size--
	}

}
相关推荐
百事老饼干10 分钟前
Java[面试题]-真实面试
java·开发语言·面试
杨荧1 小时前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
白子寰1 小时前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
linsa_pursuer1 小时前
快乐数算法
算法·leetcode·职场和发展
XuanRanDev1 小时前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
代码猪猪傻瓜coding1 小时前
力扣1 两数之和
数据结构·算法·leetcode
王俊山IT1 小时前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
为将者,自当识天晓地。1 小时前
c++多线程
java·开发语言
小政爱学习!1 小时前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript