Go 双链表
接收者是值类型好,还是指针类型好
首先要知道指针类型的接收者,有如下两个优点:
- 接收者是指针类型,可以修改原接收者的值。
- 接收者是指针类型,避免了每次调用方法时复制该值,减少了内存的消耗。对于大型结构体,这样更加高效。
方法的接收者使用值类型还是指针类型,并不是由是否修改接收者的值决定的,应该是由接收者的类型决定。方法的接收者如果是原始类型,推荐使用值类型。方法的接收者如果是非原始类型,推荐使用指针类型。
//指针接收者
package main
import "fmt"
type Usber interface {
start()
stop()
}
type Phone struct{
name string
}
func (p *Phone) start() { //指针接收者
fmt.Println(p.name,"启动")
}
func (p *Phone) stop() {
fmt.Println(p.name,"关机")
}
func main() {
p := &Phone{
name : "华为",
}
var c Usber = p //表示让Phton实现Usb接口
c.start()
c.stop()
}
&
取出地址,*
根据地址取出地址指向的值。
package main
import (
"fmt"
)
func main() {
// 准备一个字符串类型
var house = "Malibu Point 10880, 90265"
// 对字符串取地址, ptr类型为*string
ptr := &house //对字符串取地址,将指针保存到变量 ptr 中。
// 打印ptr的类型
fmt.Printf("ptr type: %T\n", ptr)
// 打印ptr的指针地址
fmt.Printf("address: %p\n", ptr)
// 对指针进行取值操作
value := *ptr //对 ptr指针变量进行取值操作,变量 value 的类型为 string。
// 取值后的类型
fmt.Printf("value type: %T\n", value)
// 指针取值后就是指向变量的值
fmt.Printf("value: %s\n", value)
}
ptr type: *string
address: 0xc0420401b0
value type: string
value: Malibu Point 10880, 90265
公共代码
D:\BaiduNetdiskDownload\5.链表实战\code>
double_node.go
package double_LinkList
//双向链表节点
type DoubleLinkNode struct {
value interface{}
prev *DoubleLinkNode //上一个节点
next *DoubleLinkNode //下一个节点
}
//新建一个节点
//value interface{} 构造一个节点
//返回一个节点 * DoubleLinkNode
func NewDoubleLinkNode(value interface{}) *DoubleLinkNode {
return &DoubleLinkNode{value, nil, nil}
}
//返回数据
func (node *DoubleLinkNode) Value() interface{} {
return node.value
}
//返回上一个节点
func (node *DoubleLinkNode) Prev() *DoubleLinkNode {
return node.prev
}
//返回下一个节点
func (node *DoubleLinkNode) PNext() *DoubleLinkNode {
return node.next
}
双链表结构
双向是验证速度
空和非空链表
双链表插入
前驱节点的地址是 p->prior
S指向P的前驱节点: s->prior = p->prior;
P的前驱的next指向S : p->prior->next = s;
phead.next.prev = node //标记上一个节点
node.next = phead.next //下一个节点
phead.next = node //标记头部节点的下一个
node.prev = phead
main.go
package main
import (
"bufio"
"fmt"
"io"
"os"
"./Single_Link"
"./double_LinkList"
//"strings"
"time"
)
func main() {
dlist := double_LinkList.NewDoubleLinkList()
node1 := double_LinkList.NewDoubleLinkNode(1)
node2 := double_LinkList.NewDoubleLinkNode(2)
node3 := double_LinkList.NewDoubleLinkNode(3)
node4 := double_LinkList.NewDoubleLinkNode(4)
node5 := double_LinkList.NewDoubleLinkNode(5)
dlist.InsertHead(node1)
dlist.InsertHead(node2)
dlist.InsertHead(node3)
dlist.InsertBack(node4)
dlist.InsertBack(node5)
// dlist.InsertHead(node4)
// dlist.InsertHead(node5)
//node6:=double_LinkList.NewDoubleLinkNode(6)
//node7:=double_LinkList.NewDoubleLinkNode(6)
//dlist.InsertValueHead(node3,node6)
fmt.Println(dlist.String())
//dlist.InsertValueBack(node3,node6)
//dlist.InsertValueHead(node3,node7)
//dlist.InsertValueBackByValue(3,node7)
//dlist.DeleteNode(node2)
//dlist.DeleteNodeAtindex(3)
//fmt.Println(dlist.String())
}
先有phead,下一个节点指向300100 ,它的前置节点是nil,下一个节点是300200,
指定一个节点的插入
下面这个是:指定一个节点尾插入法
下面这个是:指定一个节点头插入法
double_LinkList.go
package double_LinkList
import (
"fmt"
"strings"
)
//双链表的基本结构
type DoubleLinkList struct {
head *DoubleLinkNode
length int //绑定长度
}
//新建一个双链表
func NewDoubleLinkList() *DoubleLinkList {
head := NewDoubleLinkNode(nil)
//返回对象
return &DoubleLinkList{head, 0}
}
//返回链表长度
func (dlist *DoubleLinkList) Getlength() int {
return dlist.length
}
//返回第一个节点
func (dlist *DoubleLinkList) GetFirstNode() *DoubleLinkNode {
return dlist.head.next
}
//头部插入数据 node插入的新数据
func (dlist *DoubleLinkList) InsertHead(node *DoubleLinkNode) {
phead := dlist.head //头节点
//只有一个节点,他上一个还是下一个都是nil
if phead.next == nil {
node.next = nil //nil node.next = phead.next = nill
phead.next = node //只有一个节点直接链接上
node.prev = phead //上一个节点
dlist.length++
} else {
phead.next.prev = node //标记上一个节点
node.next = phead.next //下一个节点
phead.next = node //标记头部节点的下一个
node.prev = phead
dlist.length++
}
}
//尾部插入法
func (dlist *DoubleLinkList) InsertBack(node *DoubleLinkNode) {
phead := dlist.head //头节点
if phead.next == nil {
node.next = nil //nil
phead.next = node //只有一个节点直接链接上
node.prev = phead //上一个节点
dlist.length++
} else {
for phead.next != nil {
phead = phead.next //循环下去
}
phead.next = node //后缀
node.prev = phead //前缀
dlist.length++
}
}
func (dlist *DoubleLinkList) String() string {
var listString1 string
var listString2 string
phead := dlist.head
for phead.next != nil {
//正向循环
listString1 += fmt.Sprintf("%v-->", phead.next.value)
phead = phead.next //继续循环
}
listString1 += fmt.Sprintf("nil")
listString1 += "\n"
for phead != dlist.head {
//反向循环
listString2 += fmt.Sprintf("<--%v", phead.value)
phead = phead.prev
}
listString1 += fmt.Sprintf("nil")
return listString1 + listString2 + "\n" //打印链表字符串
}
func (dlist *DoubleLinkList) InsertValueBack(dest *DoubleLinkNode, node *DoubleLinkNode) bool {
phead := dlist.head
for phead.next != nil && phead.next != dest { //循环查找
phead = phead.next
}
if phead.next == dest {
if phead.next.next != nil {
phead.next.next.prev = node //500100
}
node.next = phead.next.next //300300
phead.next.next = node //500100
node.prev = phead.next //300200
//dlist.head=phead
dlist.length++
return true
} else {
return false
}
}
func (dlist *DoubleLinkList) InsertValueHead(dest *DoubleLinkNode, node *DoubleLinkNode) bool {
phead := dlist.head
for phead.next != nil && phead.next != dest { //循环查找
phead = phead.next
}
//如果它的下一个节点等于dest,就是相等
if phead.next == dest {
if phead.next != nil { //这是再300200前,插入400500
phead.next.prev = node //400500
}
node.next = phead.next //300100
node.prev = phead //300200
phead.next = node //400500
//dlist.head=phead
dlist.length++
return true
} else { //没有找到就是删除
return false
}
}
//指定一个节点尾部插入 dest是指定的节点 bool是成功还是失败
func (dlist *DoubleLinkList) InsertValueBackByValue(dest interface{}, node *DoubleLinkNode) bool {
phead := dlist.head
//我这个下一个节点不等于nil
for phead.next != nil && phead.next.value != dest { //循环查找
phead = phead.next //找到了
}
if phead.next.value == dest {
//找到的值下一个节点不等于nil
if phead.next.next != nil {
phead.next.next.prev = node //500100
}
node.next = phead.next.next //300300
phead.next.next = node //500100
node.prev = phead.next //300200
//dlist.head=phead
dlist.length++
return true
} else {
return false
}
}
//指定一个节点头部插入 dest是指定的节点 bool是成功还是失败
func (dlist *DoubleLinkList) InsertValueHeadByValue(dest interface{}, node *DoubleLinkNode) bool {
phead := dlist.head
for phead.next != nil && phead.next.value != dest { //循环查找
phead = phead.next
}
if phead.next.value == dest {
if phead.next != nil {
phead.next.prev = node //400500
}
node.next = phead.next //300100
node.prev = phead //300200
phead.next = node //400500
//dlist.head=phead
dlist.length++
return true
} else {
return false
}
}
//插入一个索引返回节点的大小
func (dlist *DoubleLinkList) GetNodeAtindex(index int) *DoubleLinkNode {
if index > dlist.length-1 || index < 0 {
return nil
}
phead := dlist.head //它是做的查找
for index > -1 {
phead = phead.next //一直循环下去
index-- //计算位置
}
return phead //符合条件返回phead
}
func (dlist *DoubleLinkList) DeleteNode(node *DoubleLinkNode) bool {
if node == nil {
return false
} else {
phead := dlist.head
for phead.next != nil && phead.next != node {
phead = phead.next //循环查找
}
if phead.next == node {
if phead.next.next != nil {
phead.next.next.prev = phead //设置pre
}
phead.next = phead.next.next //设置next
dlist.length--
return true
} else {
return false
}
return true
}
}
func (dlist *DoubleLinkList) DeleteNodeAtindex(index int) bool {
if index > dlist.length-1 || index < 0 {
return false
}
phead := dlist.head
for index > 0 {
phead = phead.next
index-- //计算位置
}
if phead.next.next != nil {
phead.next.next.prev = phead //设置pre
}
phead.next = phead.next.next //设置next
dlist.length--
return true
}
func (dlist *DoubleLinkList) FindString(inputstr string) {
phead := dlist.head.next
for phead.next != nil {
//正向循环
if strings.Contains(phead.value.(string), inputstr) {
fmt.Println(phead.value.(string))
}
phead = phead.next
}
}
需要深拷贝一个节点重新操作,一个节点不能放到两个位置,如果放到两个位置就重合了。
main.go
package main
import (
"bufio"
"fmt"
"io"
"os"
"./Single_Link"
"./double_LinkList"
//"strings"
"time"
)
func main() {
dlist := double_LinkList.NewDoubleLinkList()
node1 := double_LinkList.NewDoubleLinkNode(1)
node2 := double_LinkList.NewDoubleLinkNode(2)
node3 := double_LinkList.NewDoubleLinkNode(3)
node4 := double_LinkList.NewDoubleLinkNode(4)
node5 := double_LinkList.NewDoubleLinkNode(5)
dlist.InsertHead(node1)
dlist.InsertHead(node2)
dlist.InsertHead(node3)
dlist.InsertHead(node4)
dlist.InsertHead(node5)
// dlist.InsertHead(node4)
// dlist.InsertHead(node5)
//一个节点不能放到两个位置,如果放到两个位置就重合了。
node6 := double_LinkList.NewDoubleLinkNode(6)
node7 := double_LinkList.NewDoubleLinkNode(7)
//dlist.InsertValueHead(node3,node6)
//fmt.Println(dlist.String())
dlist.InsertValueBack(node3, node6)
dlist.InsertValueHead(node3, node7)
//dlist.InsertValueBackByValue(3,node7)
//dlist.DeleteNode(node2)
//dlist.DeleteNodeAtindex(3)
fmt.Println(dlist.String())
}
按照数据的位置插入,从后往前数第三个位置插入7
double_LinkList.go
//指定一个节点尾部插入 dest是指定的节点 bool是成功还是失败
func (dlist *DoubleLinkList) InsertValueBackByValue(dest interface{}, node *DoubleLinkNode) bool {
phead := dlist.head
//我这个下一个节点不等于nil
for phead.next != nil && phead.next.value != dest { //循环查找
phead = phead.next //找到了
}
if phead.next.value == dest {
//找到的值下一个节点不等于nil
if phead.next.next != nil {
phead.next.next.prev = node //500100
}
node.next = phead.next.next //300300
phead.next.next = node //500100
node.prev = phead.next //300200
//dlist.head=phead
dlist.length++
return true
} else {
return false
}
}
//指定一个节点头部插入 dest是指定的节点 bool是成功还是失败
func (dlist *DoubleLinkList) InsertValueHeadByValue(dest interface{}, node *DoubleLinkNode) bool {
phead := dlist.head
for phead.next != nil && phead.next.value != dest { //循环查找
phead = phead.next
}
if phead.next.value == dest {
if phead.next != nil {
phead.next.prev = node //400500
}
node.next = phead.next //300100
node.prev = phead //300200
phead.next = node //400500
//dlist.head=phead
dlist.length++
return true
} else {
return false
}
}
package main
import (
"bufio"
"fmt"
"io"
"os"
"./Single_Link"
"./double_LinkList"
//"strings"
"time"
)
func main() {
dlist := double_LinkList.NewDoubleLinkList()
node1 := double_LinkList.NewDoubleLinkNode(1)
node2 := double_LinkList.NewDoubleLinkNode(2)
node3 := double_LinkList.NewDoubleLinkNode(3)
node4 := double_LinkList.NewDoubleLinkNode(4)
node5 := double_LinkList.NewDoubleLinkNode(5)
dlist.InsertHead(node1)
dlist.InsertHead(node2)
dlist.InsertHead(node3)
dlist.InsertHead(node4)
dlist.InsertHead(node5)
// dlist.InsertHead(node4)
// dlist.InsertHead(node5)
//一个节点不能放到两个位置,如果放到两个位置就重合了。
node6 := double_LinkList.NewDoubleLinkNode(6)
node7 := double_LinkList.NewDoubleLinkNode(7)
//dlist.InsertValueHead(node3,node6)
//fmt.Println(dlist.String())
// dlist.InsertValueBack(node3, node6)
// dlist.InsertValueHead(node3, node7)
//按照数据的位置插入,从后往前数第三个位置插入7
dlist.InsertValueBackByValue(3, node7)
//dlist.DeleteNode(node2)
//dlist.DeleteNodeAtindex(3)
fmt.Println(dlist.String())
}
双链表删除
按照节点删除
D:\BaiduNetdiskDownload\5.链表实战\code\double_LinkList.go>
//按照节点删除
func (dlist *DoubleLinkList) DeleteNode(node *DoubleLinkNode) bool {
if node == nil {
return false
} else {
phead := dlist.head //查找节点
for phead.next != nil && phead.next != node {
phead = phead.next //循环查找
}
if phead.next == node {
if phead.next.next != nil { //不是第一个节点
phead.next.next.prev = phead //设置pre 就是300100
}
phead.next = phead.next.next //设置next phead.next的下一个节点是300300,代码是phead.next.next这么写的
dlist.length--
return true
} else {
return false
}
return true
}
}
按照索引编号删除
D:\BaiduNetdiskDownload\5.链表实战\code\double_LinkList.go>
//按照索引编号删除
func (dlist *DoubleLinkList) DeleteNodeAtindex(index int) bool {
if index > dlist.length-1 || index < 0 {
return false
}
phead := dlist.head
for index > 0 {
phead = phead.next
index-- //计算位置
}
if phead.next.next != nil {
phead.next.next.prev = phead //设置pre
}
phead.next = phead.next.next //设置next
dlist.length--
return true
}
main.go
package main
import (
"bufio"
"fmt"
"io"
"os"
"./Single_Link"
"./double_LinkList"
//"strings"
"time"
)
func main() {
dlist := double_LinkList.NewDoubleLinkList()
node1 := double_LinkList.NewDoubleLinkNode(1)
node2 := double_LinkList.NewDoubleLinkNode(2)
node3 := double_LinkList.NewDoubleLinkNode(3)
node4 := double_LinkList.NewDoubleLinkNode(4)
node5 := double_LinkList.NewDoubleLinkNode(5)
dlist.InsertHead(node1)
dlist.InsertHead(node2)
dlist.InsertHead(node3)
dlist.InsertHead(node4)
dlist.InsertHead(node5)
// dlist.InsertHead(node4)
// dlist.InsertHead(node5)
//一个节点不能放到两个位置,如果放到两个位置就重合了。
// node6 := double_LinkList.NewDoubleLinkNode(6)
// node7 := double_LinkList.NewDoubleLinkNode(7)
//dlist.InsertValueHead(node3,node6)
//fmt.Println(dlist.String())
// dlist.InsertValueBack(node3, node6)
// dlist.InsertValueHead(node3, node7)
//按照数据的位置插入,从后往前数第三个位置插入7
// dlist.InsertValueBackByValue(3, node7)
dlist.DeleteNode(node2)
//dlist.DeleteNodeAtindex(3)
fmt.Println(dlist.String())
}
从txt里面查找内容
double_LinkList.go
package double_LinkList
import (
"fmt"
"strings"
)
//双链表的基本结构
type DoubleLinkList struct {
head *DoubleLinkNode
length int //绑定长度
}
//新建一个双链表
func NewDoubleLinkList() *DoubleLinkList {
head := NewDoubleLinkNode(nil)
//返回对象
return &DoubleLinkList{head, 0}
}
//返回链表长度
func (dlist *DoubleLinkList) Getlength() int {
return dlist.length
}
//返回第一个节点
func (dlist *DoubleLinkList) GetFirstNode() *DoubleLinkNode {
return dlist.head.next
}
//头部插入数据 node插入的新数据
func (dlist *DoubleLinkList) InsertHead(node *DoubleLinkNode) {
phead := dlist.head //头节点
//只有一个节点,他上一个还是下一个都是nil
if phead.next == nil {
node.next = nil //nil node.next = phead.next = nill
phead.next = node //只有一个节点直接链接上
node.prev = phead //上一个节点
dlist.length++
} else {
phead.next.prev = node //标记上一个节点
node.next = phead.next //下一个节点
phead.next = node //标记头部节点的下一个
node.prev = phead
dlist.length++
}
}
//尾部插入法
func (dlist *DoubleLinkList) InsertBack(node *DoubleLinkNode) {
phead := dlist.head //头节点
if phead.next == nil {
node.next = nil //nil
phead.next = node //只有一个节点直接链接上
node.prev = phead //上一个节点
dlist.length++
} else {
for phead.next != nil {
phead = phead.next //循环下去
}
phead.next = node //后缀
node.prev = phead //前缀
dlist.length++
}
}
func (dlist *DoubleLinkList) String() string {
var listString1 string
var listString2 string
phead := dlist.head
for phead.next != nil {
//正向循环
listString1 += fmt.Sprintf("%v-->", phead.next.value)
phead = phead.next //继续循环
}
listString1 += fmt.Sprintf("nil")
listString1 += "\n"
for phead != dlist.head {
//反向循环
listString2 += fmt.Sprintf("<--%v", phead.value)
phead = phead.prev
}
listString1 += fmt.Sprintf("nil")
return listString1 + listString2 + "\n" //打印链表字符串
}
func (dlist *DoubleLinkList) InsertValueBack(dest *DoubleLinkNode, node *DoubleLinkNode) bool {
phead := dlist.head
for phead.next != nil && phead.next != dest { //循环查找
phead = phead.next
}
if phead.next == dest {
if phead.next.next != nil {
phead.next.next.prev = node //500100
}
node.next = phead.next.next //300300
phead.next.next = node //500100
node.prev = phead.next //300200
//dlist.head=phead
dlist.length++
return true
} else {
return false
}
}
//指定一个节点尾部插入 dest是指定的节点 bool是成功还是失败
func (dlist *DoubleLinkList) InsertValueHead(dest *DoubleLinkNode, node *DoubleLinkNode) bool {
phead := dlist.head
for phead.next != nil && phead.next != dest { //循环查找
phead = phead.next
}
//如果它的下一个节点等于dest,就是相等
if phead.next == dest {
if phead.next != nil { //这是再300200前,插入400500
phead.next.prev = node //400500
}
node.next = phead.next //300100
node.prev = phead //300200
phead.next = node //400500
//dlist.head=phead
dlist.length++
return true
} else { //没有找到就是删除
return false
}
}
//指定一个节点尾部插入 dest是指定的节点 bool是成功还是失败
func (dlist *DoubleLinkList) InsertValueBackByValue(dest interface{}, node *DoubleLinkNode) bool {
phead := dlist.head
//我这个下一个节点不等于nil
for phead.next != nil && phead.next.value != dest { //循环查找
phead = phead.next //找到了
}
if phead.next.value == dest {
//找到的值下一个节点不等于nil
if phead.next.next != nil {
phead.next.next.prev = node //500100
}
node.next = phead.next.next //300300
phead.next.next = node //500100
node.prev = phead.next //300200
//dlist.head=phead
dlist.length++
return true
} else {
return false
}
}
//指定一个节点头部插入 dest是指定的节点 bool是成功还是失败
func (dlist *DoubleLinkList) InsertValueHeadByValue(dest interface{}, node *DoubleLinkNode) bool {
phead := dlist.head
for phead.next != nil && phead.next.value != dest { //循环查找
phead = phead.next
}
if phead.next.value == dest {
if phead.next != nil {
phead.next.prev = node //400500
}
node.next = phead.next //300100
node.prev = phead //300200
phead.next = node //400500
//dlist.head=phead
dlist.length++
return true
} else {
return false
}
}
//插入一个索引返回节点的大小
func (dlist *DoubleLinkList) GetNodeAtindex(index int) *DoubleLinkNode {
if index > dlist.length-1 || index < 0 {
return nil
}
phead := dlist.head //它是做的查找
for index > -1 {
phead = phead.next //一直循环下去
index-- //计算位置
}
return phead //符合条件返回phead
}
//按照节点删除
func (dlist *DoubleLinkList) DeleteNode(node *DoubleLinkNode) bool {
if node == nil {
return false
} else {
phead := dlist.head //查找节点
for phead.next != nil && phead.next != node {
phead = phead.next //循环查找
}
if phead.next == node {
if phead.next.next != nil { //不是第一个节点
phead.next.next.prev = phead //设置pre 就是300100
}
phead.next = phead.next.next //设置next phead.next的下一个节点是300300,代码是phead.next.next这么写的
dlist.length--
return true
} else {
return false
}
return true
}
}
//按照索引编号删除
func (dlist *DoubleLinkList) DeleteNodeAtindex(index int) bool {
if index > dlist.length-1 || index < 0 {
return false
}
phead := dlist.head
for index > 0 {
phead = phead.next
index-- //计算位置
}
if phead.next.next != nil {
phead.next.next.prev = phead //设置pre
}
phead.next = phead.next.next //设置next
dlist.length--
return true
}
func (dlist *DoubleLinkList) FindString(inputstr string) {
phead := dlist.head.next //头节点是为空的,所有加个next
for phead.next != nil {
//正向循环 切换字符串,查找inputstr
if strings.Contains(phead.value.(string), inputstr) {
fmt.Println(phead.value.(string))
}
phead = phead.next
}
}
main.go
package main
import (
"bufio"
"fmt"
"io"
"os"
"./Single_Link"
"./double_LinkList"
//"strings"
"time"
)
func main() {
pathlist := []string{"D:\\BaiduNetdiskDownload\\5.链表实战\\猴岛游戏社区\\houdao\\1_1.txt",
"D:\\BaiduNetdiskDownload\\5.链表实战\\猴岛游戏社区\\houdao\\1_2.txt",
"D:\\BaiduNetdiskDownload\\5.链表实战\\猴岛游戏社区\\houdao\\1_3.txt"}
dlist := double_LinkList.NewDoubleLinkList()
for i := 0; i < len(pathlist); i++ {
path := pathlist[i] //路径
sqlfile, _ := os.Open(path) //打开文件
br := bufio.NewReader(sqlfile) //读取文件对象
for {
line, _, end := br.ReadLine()
if end == io.EOF { //文件结束跳出循环
break
}
linestr := string(line) //转化为字符串
node := double_LinkList.NewDoubleLinkNode(linestr) //新建一个节点
dlist.InsertHead(node) //插入节点
}
}
fmt.Println("内存载入完成", dlist.Getlength())
for {
fmt.Println("请输入要查询的用户名")
var inputstr string
fmt.Scanln(&inputstr) //用户输入
starttime := time.Now()
dlist.FindString(inputstr)
fmt.Println("本次查询用了", time.Since(starttime))
}
}