首页 > 编程语言 >【算法-链表】Go语言实现

【算法-链表】Go语言实现

时间:2023-01-23 13:55:33浏览次数:39  
标签:pre head right cur nil Next 链表 算法 Go

0、go语言 自定义 链表节点

type Node struct {
	Data int
	Next *Node
}

type DoubleNode struct {
	Data int 
	Next *DoubleNode
	Pre  *DoubleNode
}

1、单链表反转

1)遍历到当前节点cur,先获取next节点,将当前节点的next指向前一个节点pre。更新当前节点为next,所以需要一个pre初始化为nil的变量。
2)终止条件就是cur节点为nil

错误点:未更新pre。。

func ReverseLinkedList(head *Node) *Node{
	var pre *Node
	var next *Node
	for head != nil {
		next = head.Next
		head.Next = pre
		pre = head
		head = next
	}
	return pre 
}

image
这个打败是太假了。有的打败0%。

image

2、双链表反转

  1. 先获取next节点。把当前节点cur的next指向pre节点,pre节点的pre指向cur节点。
  2. 更新 pre、cur节点
  3. 终止条件,cur = nil
func ReverseDoubleLinkedList(head *DoubleNode) *DoubleNode{
	var pre *DoubleNode
	var next *DoubleNode
	for head != nil {
		next = head.Next
		head.Next = pre 
		pre.Pre = head 
		pre = head 
		head = next
	}
	return pre 
}

不出意外的话,出意外了
image
空指针,因为用到pre.pre了。必须保证pre不为nil,简单点,从第二个节点开始遍历。pre初始化为第一个节点。

func ReverseDoubleLinkedList(head *DoubleNode) *DoubleNode {
	if head == nil {
		return nil
	}
	var pre *DoubleNode
	pre = head
	head = head.Next
	var next *DoubleNode
	for head != nil {
		next = head.Next
		head.Next = pre
		pre.Pre = head
		pre = head
		head = next
	}
	return pre
}

再跑:死循环了。。很明显还需要
打印返回的新的首节点,发现Next和Pre是同一个对象。后置处理:应该要把pre.pre置空。新的首节点的Pre肯定是空的,这里不是循环双向链表。
image

func ReverseDoubleLinkedList(head *DoubleNode) *DoubleNode {
	if head == nil {
		return nil
	}
	var pre *DoubleNode
	pre = head
	head = head.Next
	pre.Next = nil //需要将末尾节点的Next节点置空。不然死循环。
	var next *DoubleNode

	for head != nil {
		next = head.Next
		head.Next = pre
		pre.Pre = head
		pre = head
		head = next

	}
	pre.Pre = nil
	return pre
}

image

错误点:新的尾节点的next置空。新的首节点的pre置空。

-上面是更新当前节点的Next和Pre节点Pre.要是换一种更新,遍历到当前节点,只更新当前节点的Next和Pre.就简单了。。

func ReverseDoubleLinkedList_02(head *DoubleNode) *DoubleNode {
	if head == nil {
		return nil
	}
	var pre *DoubleNode
	var next *DoubleNode

	for head != nil {
		next = head.Next
		head.Next = pre
		head.Pre = next
		pre = head
		head = next
	}
	return pre
}

image
这种基本题,不训练还是不行。唉。太笨了。

3、打印两个有序链表的公共部分

  1. 谁小谁右移
  2. 一样打印,都右移
  3. 终止条件:其中任何一个遍历完了。
func PrintCommonLinkedList(head1 *Node, head2 *Node) {

	for head1 != nil && head2 != nil {
		if head1.Data == head2.Data {
			fmt.Print(head1.Data)
			head1 = head1.Next
			head2 = head2.Next
		} else if head1.Data > head2.Data {
			head2 = head2.Next
		} else {
			head1 = head1.Next
		}
	}

}
  • 技巧1:额外哈希表记录
  • 技巧2:快慢指针,双指针
  • 技巧3:增加一个首节点好处理数据。

4、判断一个链表是否为回文结构

方法1:使用额外空间,

  1. 使用一个栈,把链表先入栈,然后出栈和链表一一对比。如果有不一样的:false.如果遍历完都一样,就true
func IsPalindromLinkedList_01(head *Node) bool {
	arr := make([]int, 10)
	i := 0
	cur := head
	for cur != nil {
		arr[i] = cur.Data
		i++
		cur = cur.Next
	}
	i--
	cur = head
	for i >= 0 && cur != nil {
		if arr[i] != cur.Data {
			return false
		}

		i--
		cur = cur.Next
	}
	return true

}

方法二,快慢指针。节省一半空间

  1. 慢指针slow一次走一步,快指针fast一次走俩步,如果其中一个next指针为空,停止,慢指针走的数都进栈。
  2. 如果是奇数个,那么慢指针正好在最中间。如果是偶数个,那么慢指针在左半边最后一个。
  3. 慢指针的下一个数依次和栈里的数一一比较。

错误示例:

func IsPalindromLinkedList_02(head *Node) bool {
	arr := make([]int, 10)
	i := 0
	slow := head
	fast := head
	for slow.Next != nil && fast.Next.Next != nil {
		arr[i] = slow.Data
		i++
		slow = slow.Next
		fast = fast.Next.Next
	}
	i--
	right_first := slow.Next
	for i >= 0 {
		if arr[i] != right_first.Data {
			return false
		}
		i--
		right_first = right_first.Next
	}
	return true
}

image

  • 思路2: right表示右边第一个元素。 cur每次都俩步,right每次走一步。cur.next 为空或者cur.next.next为空,right已经到了最右边第一个。这里必须先判断cur.next不为空,再判断cur.next.next。循环完成之后。将right和right后面的元素全部入栈,然后依次出栈和head开始比较。
func IsPalindromLinkedList_03(head *Node) bool {

	if head == nil || head.Next == nil {
		return false
	}

	cur := head
	right := head.Next

	// right每次向右移动一个,cur每次向右移动俩个

	for cur.Next != nil && cur.Next.Next != nil {
		right = right.Next  //能进来说明right 不为空
		cur = cur.Next.Next // 更新cur. cur为空了。right走到右边第一个
	}

	// 把right后边的元素都入栈
	arr := make([]int, 10)
	i := 0

	for right != nil {
		arr[i] = right.Data
		right = right.Next
		i++
	}

	i--
	// 出栈和头节点开始依次对比,直到栈中无元素。
	for i >= 0 {
		if arr[i] != head.Data {
			return false
		}

		i--
		head = head.Next
	}
	return true
}

方法3:额外空间为0.

遍历的时候,顺便把左或右半部分的链表翻转了。
然后开始从中间像俩边比较
还要恢复。。

func IsPalindromLinkedList_04(head *Node) bool {

   if head == nil || head.Next == nil {
   	return true
   }

   // right := head.Next  //right 从 next出发。不好获取左边最后一个元素。
   right := head //从 head出发,遍历完之后。right是左边最后一个元素
   cur := head

   for cur.Next != nil && cur.Next.Next != nil {
   	right = right.Next
   	cur = cur.Next.Next
   }

   left_last := right //保存左边最后一个元素,也有可能是中间值

   right_first := right.Next // 右边第一个值

   left_last.Next = nil // 断开

   right_last := ReverseLinkedList(right_first) //将右半部分翻转

   // 比较, 如果其中一个到头了。就结束
   res := true

   right_node := right_last
   left_node := head

   for right_node != nil && left_node != nil {
   	if right_node.Data != left_node.Data {
   		res = false
   	}
   	right_node = right_node.Next
   	left_node = left_node.Next
   }

   // 右半部分再翻转回来。
   right_first = ReverseLinkedList(right_last)

   left_last.Next = right_first // 左右连接
   return res

}

5、将单向链表按某值划分成左边小、中间相等、右边大的形式

方法1:就初始化三个新的链表,然后拼接。有开辟新的内存空间

方法2:使用6个变量,lh:小于pv的头节点,ll:小于pv的尾节点。 eh:等于pv的头节点,el:等于pv的尾节点, mh:大于pv的头节点,ml:大于pv的尾节点

标签:pre,head,right,cur,nil,Next,链表,算法,Go
From: https://www.cnblogs.com/clllll/p/17064969.html

相关文章

  • polygon部署 mainnet 0.3.x
    环境要求内存:16-32GBCPU:4-8核CPU(t3xLarge)存储:至少650GBSSD(确保它是可扩展的)安装环境依赖安装编译环境~#sudoapt-getinstallbuild-essential-y安装go~#wgethttps:......
  • 算法--2023.1.22
    1.力扣287--寻找重复数classSolution{//环形链表2的变形:数组游标是指针,数组中的元素值是该节点指向下一个节点的指针//该问题可以转化为找到环的入口pu......
  • 算法--2023.1.23
    1.力扣300--最长递增子序列classSolution{publicintlengthOfLIS(int[]nums){//贪心算法,基本思路:dp数组维护长度为下表i的最长子序列的最后一个值的......
  • 7个流行的强化学习算法及代码实现
    目前流行的强化学习算法包括Q-learning、SARSA、DDPG、A2C、PPO、DQN和TRPO。这些算法已被用于在游戏、机器人和决策制定等各种应用中,并且这些流行的算法还在不断发展......
  • js mouse_go_canvas特效
    只需要js代码就行,避免id重复/***id:mouse_go_canvas*/constfillColor="#7400a1" constmouse_go_canvas=document.createElement("canvas")mouse_go_canv......
  • 软件的基本是要处理好”算法“及其基础(三)delphi 10.4.1字符串工具单元及其函数
     //:关于字符串的定义: _RawByteStr=RawByteString; {$IFDEFNEXTGEN}   UTF8String=type_AnsiString(65001);   RawByteString=type_AnsiString($f......
  • C# 简单实现 奇葩排序中的算盘排序(算珠排序)算法
    Console.WriteLine("HelloWorld!");int[]arr={1,3,4,0,22,4,0,6,3,10,8,6,7};Console.WriteLine(string.Join(",",arr.ToList(......
  • 两两交换链表中的结点--力扣
      这道题运用了递归的方法,很明显当链表为空,或是只存在一个元素时,程序返回头指针。这个条件可以用来当递归的终止条件。在1.看完题解后,我是按照从后往前推理解的(递归的......
  • 【算法-计数排序和桶排序】Go语言实现
    计数排序新创建一个计数数组,size=Max遍历数组,值是索引。遍历计数数组,依次排列。funcCountSort(arr[]int){ count_arr:=make([]int,10) for_,value:=ra......
  • (18)go-micro微服务ELK介绍
    目录一什么是ELK二Beats的六种工具三ELK系统的特点四ELK+beats系统架构五ELK优点六最后一什么是ELKELK是三个[开源软件]的缩写,分别表示:Elasticsearch,Logstash,......