golang 双向链表的实现增删查改+ 双指针双向查找

package main

import (
	"context"
	//"time"

	//"context"
	//"container/list"
	"fmt"
)

//这是一个node的 构造函数
func nodeCreater(val string) *node {
	return &node{
		val: val,
	}
}

//双向链表
type node struct {
	val  string
	prev *node
	next *node
}

//普通遍历由head 到tail 遍历
func (s *node) trans() {
	for s != nil {
		fmt.Println(*s)
		s = s.next
	}
}

//反向遍历
func (s *node) rtrans(r *node) {
	for r != nil {
		fmt.Println(*r)
		r = r.prev
	}
}

//关于正向查找和反向查找,理论上比单链表至少快一倍
//正向查找
func iteratesByNext(ctx context.Context, ret chan *node, val string, n *node) {
	for n != nil {
		select {
		case <-ctx.Done():
		default:
			if n.val == val {
				//fmt.Println("n:", n.val)
				ret <- n
				return
			}
			//fmt.Println("n:", n.val)
			n = n.next
		}
	}
}

//反向查找
func iteratesByPrev(ctx context.Context, ret chan *node, val string, p *node) {
	//t := time.NewTicker(time.Microsecond * 300).C //延时300ms 不然太快了, 来不及看结果
	for p != nil {
		select {
		case <-ctx.Done():
		// case <-t:
		// 	if p.val == val {
		// 		ret <- p
		// 		return
		// 	}
		// 	//fmt.Println("P:", p.val)
		// 	p = p.prev
		// 	//default:
		default:
			if p.val == val {
				ret <- p
				return
			}
			//fmt.Println("P:", p.val)
			p = p.prev
			//default:
		}
	}
}

//查找,双向同时查找
func twoRoutersFind(val string, head, tail *node) *node {
	ctx, cancel := context.WithCancel(context.Background())
	ret := make(chan *node)
	go iteratesByNext(ctx, ret, val, head)
	go iteratesByPrev(ctx, ret, val, tail)
	for {
		select {
		case val := <-ret:
			//fmt.Println(*val)
			cancel() //结束所有协程
			return val
		default:
		}
	}
}

func delNode(p2 *node) {
	p1 := p2.prev
	p3 := p2.next
	p3.prev = p1
	p1.next = p3
}

func insertNode(p2 *node) {
	p3 := nodeCreater("insert")
	p1 := p2.prev
	p1.next = p3
	p2.prev = p3
	p3.prev = p1
	p3.next = p2
}

func main() {
	head := &node{
		val:  "head",
		prev: nil,
	}
	tail := head
	for i := 0; i < 10; i++ {
		stu := &node{
			val: fmt.Sprintf("val%d", i),
		}
		tail.next = stu
		stu.prev = tail
		tail = stu
	}
	//普通遍历
	//head.trans()
	//反向遍历
	head.rtrans(tail)
	//双向遍历查找
	val := twoRoutersFind("val3", head, tail)
	fmt.Println("--find out this val:", val)
	// delNode(val)
	// head.trans()
	// head.rtrans(tail)

	insertNode(val)

	head.trans()
	head.rtrans(tail)
}

其他的都很简单。
主要是查找
//t := time.NewTicker(time.Microsecond * 300).C //延时300ms 不然太快了, 来不及看结果
这句是为了看一下,如果双指针(head tail )同时查找的话,如果一条路线找到结果,就结束两条协程。 加个延时看看是否正确实现了

	// case <-t:
	// 	if p.val == val {
	// 		ret <- p
	// 		return
	// 	}
	// 	//fmt.Println("P:", p.val)
	// 	p = p.prev
	// 	//default:

这里是测试代码, 如果测试的话,需要打开这段代码,注释掉default 代码

另外浅谈下环链表:
就是
head.prev = tail
tail.next = head

就是环形链表了, 遍历上显然
// head.trans()
// head.rtrans(tail)
全部都不能用了。
其他的都一样

#另外这段代码有bug , 显然如果是head 节点,或者 tail 节点的时候会出bug , 请自行加个if 吧, 参考单链表的实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值