题目:
以上四种情况类似,均通过快慢指针的初始点,以及移动条件控制最终的输出
代码:
package main
import (
"fmt"
)
//链表本身,包含长度,头结点和尾节点,对于一个双向链表,
//我们只关注它的haea和tail,head和tail是一个个具体的节点
type LinkedList struct {
len int
head *LinkedNode
tail *LinkedNode
}
//链表中的一个节点的结构,包含节点的数据,前向指针,后向指针,指向的也是一个节点本身
type LinkedNode struct {
data int
next *LinkedNode
prev *LinkedNode
}
// type Data struct{
// key string
// data int
// }
//所有的操作都基于指针
func NewLinkedList() *LinkedList {
return &LinkedList{
len: 0,
head: nil,
tail: nil,
}
}
//追加一个节点,链表没有头结点就把自己设为链表的头结点,头尾指针都指向自己
//有头结点就把自己放在最后,1先把自己的prev指向原来的tail,2把原来的tail的next指向自己,3把链表的tail设为自己
func (ll *LinkedList)Add(node *LinkedNode) {
// node := &LinkedNode{
// data: data,
// }
// fmt.Printf("hhhhhhead%v\n", ll.head)
if ll.head==nil{
ll.tail=node
ll.head=node
}else{
// fmt.Printf("tttttail%v\n", ll.tail)
node.prev=ll.tail
ll.tail.next=node
ll.tail=node
}
ll.len++//记得更新长度
}
//奇数返回中点 偶数返回上中点
func Midorupmid(head LinkedNode) LinkedNode{
if &head ==nil || head.next == nil || head.next.next == nil{//只有一个节点或两个节点时,返回头结点
return head
}
//慢指针一个定位在第二个节点,快指针定位在第三个节点
slow:=head.next
fast:=head.next.next
for fast.next != nil && fast.next.next !=nil{
slow=slow.next
fast=fast.next.next
}
return *slow
}
//1 for里面的条件是&,不是||
//2 slow和 fast在前进过程中是不等距的,不能混淆
func Midordownmid(head LinkedNode) *LinkedNode{
if &head ==nil || head.next == nil {//控制节点大于1,就可以进入下面的循环
return &head//当head等于nil,head的next也等于nil,
}
//两个指针都初始化在head.next
slow:=head.next
fast:=head.next
//节点数大于1进入
for fast.next !=nil && fast.next.next !=nil {//注意是and,必现同时满足
slow=slow.next
fast=fast.next.next//slow和fast不等距,所以不能用slow.next.next代替
// fmt.Println(slow,fast)
}
return slow
}
func beforeMidorupmid(head LinkedNode) *LinkedNode{
if &head ==nil || head.next == nil || head.next.next == nil{//节点数小于3,均不成立
return nil
}
//两个指针都定位在头节点,返回slow的前置节点
slow:=&head
fast:=&head
//节点数大于2才成立
for fast.next != nil && fast.next.next !=nil{
slow=slow.next
fast=fast.next.next
}
return slow.prev
}
func aftereMidordownmid(head LinkedNode) *LinkedNode{
if &head ==nil || head.next == nil || head.next.next == nil{//节点数小于3,均不成立
return nil
}
//两个指针都定位在头节点,返回slow的前置节点
slow:=head.next
fast:=head.next
//节点数大于2才成立
for fast.next != nil && fast.next.next !=nil{
slow=slow.next
fast=fast.next.next
}
return slow.next
}
func main(){
var head LinkedNode
head.data=18
var l1 LinkedNode
l1.data=5
var l2 LinkedNode
l2.data=20
var l3 LinkedNode
l3.data=4
var l4 LinkedNode
l4.data=3
var l5 LinkedNode
l5.data=8
var l6 LinkedNode
l6.data=12
var l7 LinkedNode
l7.data=15
list := NewLinkedList()
list.Add(&head)
list.Add(&l1)
list.Add(&l2)
list.Add(&l3)
list.Add(&l4)
list.Add(&l5)
// fmt.Println(list.head)
// fmt.Println(list.head.next)
// fmt.Println(list.head.next.next)
// fmt.Println(list.head.next.next.next)
// fmt.Println(list.tail)
fmt.Println(Midorupmid(head))
fmt.Println(Midordownmid(head))
fmt.Println(beforeMidorupmid(head))
fmt.Println(aftereMidordownmid(head))
}
链表-18 ,5,20, 4,3, 8
输出:
{20 0xc0000960a8 0xc000096078}
&{4 0xc0000960c0 0xc000096090}
&{5 0xc000096090 0xc000096060}
&{3 0xc0000960d8 0xc0000960a8}
总结:
该类题型的重点在于
1 快慢指针初始在那个点上,同一个点or一前一后
2 移动条件,何时移动,何时不移动,控制输出的节点一直落在一个快慢指针相关的点上
coding上
1,两个指针移动过程中可能不是等距的,不能互相赋值
2,for循环条件中是&