【Go】单链表
node.go
// 链表节点
type Node struct {
data interface{}
next *Node
} // 构造一个节点
func NewNode(data interface{}) *Node {
return &Node{data: data, next: nil}
}
list.go
package single_linked_list import (
"fmt"
) type SingleLinked interface {
Add(node *Node) // 在链表前面插入节点
Append(node *Node) // 在链表后面插入节点
Delete(node *Node) // 删除节点
DeleteByIndex(index int) // 根据索引删除节点
InsertBefore(data interface{}, node *Node) // 在xx之前插入节点
InsertAfter(data interface{}, node *Node) // 在xx之后插入节点
Get(index int) interface{}
Length() int
String() string
Reverse() // 反转链表
} type List struct {
head *Node // 链表头结点
length int // 链表长度
} func NewList() *List {
head := NewNode(nil)
return &List{head: head, length: 0}
} // 在链表前面插入节点
func (list *List) Add(node *Node) {
if list.head == nil {
list.head.next = node
node.next = nil
list.length++
} else {
temp := list.head // 保存头结点
node.next = temp.next // 新节点指向的节点就是原先头结点指向的节点
temp.next = node // 头结点指向新节点
list.length++
}
} // 在链表后面插入节点
func (list *List) Append(node *Node) {
if list.head == nil {
list.head.next = node
node.next = nil
list.length++
} else {
temp := list.head
for temp.next != nil { // 一直循环到链表最后一个节点
temp = temp.next
}
temp.next = node
list.length++
}
} // 在xx之前插入节点
func (list *List) InsertBefore(data interface{}, node *Node) {
temp := list.head
isFind := false
for temp.next != nil {
if temp.next.data == data { // 根据data找到其节点,在该节点之前插入新节点
isFind = true
break
}
temp = temp.next
}
if isFind {
node.next = temp.next
temp.next = node
list.length++
}
} // 在xx之后插入节点
func (list *List) InsertAfter(data interface{}, node *Node) {
temp := list.head
isFind := false
for temp.next != nil {
if temp.data == data {
isFind = true
break
}
temp = temp.next
}
if isFind {
node.next = temp.next
temp.next = node
list.length++
}
} // 删除节点
func (list *List) Delete(node *Node) {
if node == nil {
return
}
temp := list.head
// 如果下一个节点不等于要删除的节点,则循环找下去
for temp.next != nil && temp.next != node {
temp = temp.next
}
if temp.next == node {
// temp指向 要删除节点指向 的节点
temp.next = temp.next.next
list.length--
}
} // 根据索引删除节点
func (list *List) DeleteByIndex(index int) {
if index > list.length-1 || index < 0 {
return
}
temp := list.head
for index > 0 {
temp = temp.next
index--
}
temp.next = temp.next.next
list.length--
} func (list *List) Get(index int) interface{} {
if index > list.length-1 || index < 0 {
return nil
}
temp := list.head
for index > -1 {
temp = temp.next
index--
}
return temp.data
} func (list *List) Length() int {
return list.length
} // 打印链表
func (list *List) String() string {
var str string
node := list.head
for node.next != nil {
str += fmt.Sprintf("%v-->", node.next.data)
node = node.next
}
str = fmt.Sprintf("head-->%snil", str)
return str
} // 反转链表
func (list *List) Reverse() {
// 链表为空或只有1个节点
if list.head == nil || list.head.next == nil {
return
} else {
/*
------ ------ ------
head.next -> 0x01| | 0x02| | 0x03| |
| aa | ' | bb | ' | cc |
| | ' | | ' | |
| 0x02 | ' | 0x03 | ' | nil |
------ ------ ------ ------ ------ ------
| |0x01 | |0x02 | |0x03 <- head.next
| aa | ' | bb | ' | cc |
| | ' | | ' | |
| nil | ' | 0x01 | ' | 0x02 |
------ ------ ------
*/
// prev ----> curr ----> currNext
var prev *Node // 前一个节点(初始时即为 空节点)
var curr *Node = list.head.next // 当前节点(初始时即为 第1个节点)
for curr != nil {
currNext := curr.next // 暂存当前节点的下一个节点(初始时即为 第2个节点)
curr.next = prev // 当前节点指向前一个节点(初始时即让 第1个节点指向空节点;... 那么 1 <- 2 2 <- 3)
// 持续推进(循环到最后)
prev = curr // 前一个节点变成了当前节点(初始时理解为 第1个节点跑到空节点位置)
curr = currNext // 当前节点变成了下一个节点(初始时理解为 第2个节点跑到第1个节点位置)
}
list.head.next = prev
}
}
main.go
// 单链表
func main() {
var list single_linked_list.SingleLinked = single_linked_list.NewList()
n1 := single_linked_list.NewNode(1)
n2 := single_linked_list.NewNode(2)
n3 := single_linked_list.NewNode(3)
n4 := single_linked_list.NewNode(4)
n5 := single_linked_list.NewNode(5)
list.Add(n1)
list.Add(n2)
list.Add(n3)
list.Append(n4)
list.Append(n5)
fmt.Println(list) // head-->3-->2-->1-->4-->5-->nil
list.Delete(n1)
fmt.Println(list) // head-->3-->2-->4-->5-->nil
list.DeleteByIndex(2)
fmt.Println(list) // head-->3-->2-->5-->nil
list.InsertBefore(2, n1)
fmt.Println(list) // head-->3-->1-->2-->5-->nil
list.InsertAfter(2, n4)
fmt.Println(list) // head-->3-->1-->2-->4-->5-->nil
fmt.Println(list.Length()) // 5
fmt.Println(list.Get(0)) // 3
fmt.Println(list.Get(10)) // nil
list.Reverse()
fmt.Println(list) // head-->5-->4-->2-->1-->3-->nil
}
【Go】单链表的更多相关文章
- 时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法
有一个单链表,提供了头指针和一个结点指针,设计一个函数,在 O(1)时间内删除该结点指针指向的结点. 众所周知,链表无法随机存储,只能从头到尾去遍历整个链表,遇到目标节点之后删除之,这是最常规的思路和 ...
- 单链表的C++实现(采用模板类)
采用模板类实现的好处是,不用拘泥于特定的数据类型.就像活字印刷术,制定好模板,就可以批量印刷,比手抄要强多少倍! 此处不具体介绍泛型编程,还是着重叙述链表的定义和相关操作. 链表结构定义 定义单链表 ...
- Java实现单链表的各种操作
Java实现单链表的各种操作 主要内容:1.单链表的基本操作 2.删除重复数据 3.找到倒数第k个元素 4.实现链表的反转 5.从尾到头输出链表 6.找到中间节点 7.检测链表是否有环 8.在 ...
- [LeetCode] Linked List Cycle II 单链表中的环之二
Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Foll ...
- c++单链表基本功能
head_LinkNode.h /*单链表类的头文件*/#include<assert.h>#include"compare.h"typedef int status; ...
- 单链表、循环链表的JS实现
数据结构系列前言: 数据结构作为程序员的基本知识,需要我们每个人牢牢掌握.近期我也展开了对数据结构的二次学习,来弥补当年挖的坑...... 当时上课的时候也就是跟着听课,没有亲自实现任何一种数据结 ...
- C代码实现非循环单链表
C代码实现非循环单链表, 直接上代码. # include <stdio.h> # include <stdlib.h> # include <malloc.h> ...
- 分离的思想结合单链表实现级联组件:CascadeView
本文介绍自己最近做省市级联的类似的级联功能的实现思路,为了尽可能地做到职责分离跟表现与行为分离,这个功能拆分成了2个组件并用到了单链表来实现关键的级联逻辑,下一段有演示效果的gif图.虽然这是个很常见 ...
- 数据结构:单链表结构字符串(python版)添加了三个新功能
#!/urs/bin/env python # -*- coding:utf-8 -*- #异常类 class stringTypeError(TypeError): pass #节点类 class ...
- 数据结构:单链表结构字符串(python版)改进
此篇文章的replace实现了字符串类的多次匹配,但依然有些不足. 因为python字符串对象为不变对象,所以replace方法并不修改原先的字符串,而是返回修改后的字符串. 而此字符串对象时用单链表 ...
随机推荐
- Android给ListView添加侧滑菜单功能
贼简单,但是上次集成完之后忘记整理,所以写的有点简单 SwipeMenu类 继承自ViewGroup package com.onepilltest.others; import android.co ...
- 以细胞为例 说一下dfs和bfs的思路
今天发现很少写dfs.. dfs主要思想是递归 bfs主要靠队列 先说一下这个题我被阻了半个小时的地方: 1读数一定要注意scanf的吃回车 2注意数据类型为char,判断时是'0' dfs: #in ...
- Python os.tmpfile() 方法
概述 os.tmpfile() 方法用于返回一个打开的模式为(w+b)的临时文件对象,这文件对象没有文件夹入口,没有文件描述符,将会自动删除.高佣联盟 www.cgewang.com 语法 tmpfi ...
- luogu P4725 多项式对数函数(多项式 ln)
LINK:多项式对数函数 多项式 ln 如题 是一个模板题.刚学会导数 几个知识点 \([f(x)\cdot g(x)]'=f(x)'g(x)+f(x)g(x)',f(g(x))'=f'(g(x))g ...
- 牛客挑战赛 39 牛牛与序列 隔板法 容斥 dp
LINK:牛牛与序列 (牛客div1的E题怎么这么水... 还没D难. 定义一个序列合法 当且仅当存在一个位置i满足 $a_i>a_,a_j<a_$且对于所有的位置i,$1 \leq a_ ...
- Dynmaics 365 scale group
关于scale Groups的概念,在看Dynamics crm online的时候,一直不理解缩放组scale group的概念,后来查到GP也在用这个概念,想想不就是动态扩展嘛,马上顿悟了,原来如 ...
- Linux的VMWare中Centos7文件目录类命令
1.)ls命令简介 ls ---列出目前工作目录所含之文件及子目录 语法 ls [-alrtAFR] [name...] 参数 : -a 显示所有文件及目录 (ls内定将文件名或目录名称 ...
- Workerman学习笔记(一)初步认识
本文只是概念性的知识,内容比较零散,下篇文章再进行代码分析. Workerman是什么,他的优势在哪? 官方给的解释是高性能socket框架,我的个人理解是实现多进程的通讯的服务框架. 与传统的PHP ...
- 【NOI2010】超级钢琴 题解(贪心+堆+ST表)
题目链接 题目大意:求序列内长度在$[L,R]$范围内前$k$大子序列之和. ---------------------- 考略每个左端点$i$,合法的区间右端点在$[i+L,i+R]$内. 不妨暴力 ...
- 22-关键字:super
1.super 关键字可以理解为:父类的 2.可以用来调用的结构: 属性.方法.构造器 3.super调用属性.方法: 3.1 我们可以在子类的方法或构造器中.通过使用"super.属性&q ...