Go语言—利用结构体操作单链表

写在前面

在学习Go语言中的结构体实现单链表时,发现参考资料给的一些例子都是十分简单。上网查了一圈,也没有找到更多的稍微复杂一些的例子,于是结合以前学习Python操作单链表的思路,给出了Go语言的版本,仅供学习参考。

package main

import "fmt"

// ListNode 链表的节点
type ListNode struct {
	val  int
	next *ListNode
}

// is_empty判断一个链表是否为空
func (l *ListNode) is_empty() bool {
	return l.next == nil
}

// link_len 检查链表的长度
func (l *ListNode) link_len() int {
	count := 0
	cur := l.next
	for cur != nil {
		count++
		cur = cur.next
	}
	return count
}

// append 从尾部插入节点
func (l *ListNode) append(elm int) {
	node := new(ListNode)
	node.val = elm
	if l.is_empty() {
		l.next = node
	} else {
		cur := l.next
		for cur.next != nil {
			cur = cur.next
		}
		cur.next = node
	}
}

// add 从头部插入节点
func (l *ListNode) add(elm int) {
	node := new(ListNode)
	node.val = elm
	if l.is_empty() {
		l.next = node
	} else {
		node.next = l.next
		l.next = node
	}
}

// Insert 从指定位置插入节点
func (l *ListNode) Insert(pos int, elm int) {
	node := new(ListNode)
	node.val = elm

	if l.is_empty() {
		l.next = node
	} else if pos >= l.link_len() {
		l.append(elm)
	} else if pos <= 0 {
		l.add(elm)
	} else {
		count := 1
		cur := l.next
		for cur != nil {
			if pos == count {
				node.next = cur.next
				cur.next = node
				break
			} else {
				count++
				cur = cur.next
			}
		}
	}
}

// delete 删除链表中的元素
func (l *ListNode) delete(pos int) {
	if l.is_empty() {
		fmt.Println("链表为空!!!")
		return
	} else if l.link_len() == 1 {
		l.next = nil
	} else if pos <= 0 {
		l.next = l.next.next
	} else if pos >= l.link_len() {
		pre := l.next
		cur := l.next
		for cur.next != nil {
			pre = cur
			cur = cur.next
		}
		pre.next = nil
	} else {
		pre := l.next
		cur := l.next
		count := 0
		for cur.next != nil {
			if pos == count {
				pre.next = cur.next
				break
			}
			count++
			pre = cur
			cur = cur.next
		}
	}
}

// Reverse 链表逆序
func (l *ListNode) Reverse() {
	if l.is_empty() {
		fmt.Println("链表为空!!!")
		return
	} else {
		cur := l.next
		next := cur.next
		pre := new(ListNode)

		for cur.next != nil {
			cur.next = pre.next
			pre.next = cur
			cur = next
			next = cur.next
		}
		cur.next = pre.next
		l.next = cur
	}
}

// RemoveTheSame 从无序链表中移除重复项
func (l *ListNode) RemoveTheSame() {
	if l.is_empty() {
		fmt.Println("链表为空!!!")
		return
	} else {
		cur := l.next
		for cur != nil {
			next := cur.next
			pre := cur
			for next != nil {
				if next.val == cur.val {
					pre.next = next.next
					next = next.next
				} else {
					pre = next
					next = next.next
				}
			}
			cur = cur.next
		}
	}
}

// Traverse 遍历链表
func (l *ListNode) Traverse() {
	cur := l.next
	for cur != nil {
		fmt.Printf("%d ", cur.val)
		cur = cur.next
	}
	fmt.Printf("\n")
}

func main() {
	link := new(ListNode)
	fmt.Println("the link is empty?", link.is_empty())

	fmt.Println("从尾部插入节点--------")
	link.append(1)
	link.append(2)
	link.append(3)
	link.Traverse()
	fmt.Println("--------从尾部插入节点")

	fmt.Println("从头部插入节点--------")
	link.add(100)
	link.Traverse()
	fmt.Println("--------从头部插入节点")

	fmt.Println("the length of link is:", link.link_len())

	fmt.Println("从任意位置插入节点--------")
	fmt.Println("原始链表")
	link.Traverse()

	fmt.Println("↓在-1位置插入200")
	link.Insert(-1, 200)
	link.Traverse()
	fmt.Println("↓在5位置插入300")
	link.Insert(5, 300)
	link.Traverse()
	fmt.Println("↓在2位置插入666")
	link.Insert(2, 666)
	link.Traverse()
	fmt.Println("--------从任意位置插入节点")

	fmt.Println("链表反转--------")
	fmt.Println("原始链表")
	link.Traverse()
	fmt.Println("↓反转后")
	link.Reverse()
	link.Traverse()
	fmt.Println("--------链表反转")

	fmt.Println("删除链表中的重复项--------")
	link.Insert(1, 2)
	link.Insert(3, 2)
	link.append(666)
	fmt.Println("原始链表")
	link.Traverse()
	fmt.Println("删除重复元素")
	link.RemoveTheSame()
	link.Traverse()
	fmt.Println("--------删除链表中的重复项")

	fmt.Println("删除链表元素--------")
	fmt.Println("原始链表")
	link.Traverse()

	fmt.Println("↓删除第0个元素")
	link.delete(0)
	link.Traverse()

	fmt.Println("↓删除第3个元素")
	link.delete(3)
	link.Traverse()

	fmt.Println("↓删除第10个元素")
	link.delete(10)
	link.Traverse()
	fmt.Println("--------删除链表元素")
}

运行结果如下:

the link is empty? true
从尾部插入节点--------
1 2 3
--------从尾部插入节点
从头部插入节点--------
100 1 2 3
--------从头部插入节点
the length of link is: 4
从任意位置插入节点--------
原始链表
100 1 2 3
↓在-1位置插入200
200 100 1 2 3
↓在5位置插入300
200 100 1 2 3 300
↓在2位置插入666
200 100 666 1 2 3 300
--------从任意位置插入节点
链表反转--------
原始链表
200 100 666 1 2 3 300
↓反转后
300 3 2 1 666 100 200
--------链表反转
删除链表中的重复项--------
原始链表
300 2 3 2 2 1 666 100 200 666
删除重复元素
300 2 3 1 666 100 200
--------删除链表中的重复项
删除链表元素--------
原始链表
300 2 3 1 666 100 200
↓删除第0个元素
2 3 1 666 100 200
↓删除第3个元素
2 3 1 100 200
↓删除第10个元素
2 3 1 100
--------删除链表元素

本文操作单链表的思路与我的一篇博客(数据结构与算法之单链表(一))一致,有兴趣的朋友可以阅读。

最后

在力扣题库里面找了一条简单的链表题

将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
// 常规思路
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	head := new(ListNode) // 申明一个新的链表用于存储有序链表,head是头节点,代表整个链表
	cur := head           // 申明一个游标,操作的是结构体指针,所以修改有效

	for l1 != nil && l2 != nil {
		if l1.Val <= l2.Val {
			cur.Next = l1
			l1 = l1.Next
		} else {
			cur.Next = l2
			l2 = l2.Next
		}
		cur = cur.Next
	}
	// 如果链表不等长,直接将剩余追加到新链表后面
	if l1 == nil {
		cur.Next = l2
	}
	if l2 == nil {
		cur.Next = l1
	}
	return head.Next
}

// 递归
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
    if l1 == nil {
        return l2
    }

    if l2 == nil {
        return l1
    }

    head := new(ListNode)
    if l1.Val <= l2.Val {
        head = l1
        head.Next = mergeTwoLists(l1.Next, l2)
    }else{
        head = l2
        head.Next = mergeTwoLists(l1, l2.Next)
    }
    return head
}

使用递归的方法会在内存上消耗的多一点,但是不得不说go语言要比Python快多了(36ms,11.5M)。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值