内容简介:基于golang实现,有非并发实现和并发实现全排列问题,比如打印1-9的共9个字母的全排列。先输出1,然后是2-9的全排列,输出2,然后1-9中去除2的全排列。于是很自然想到递归的方法。写出伪代码:刚才实现的是go单线程执行的,改成并发版本的, 参考rob pike讲
基于golang实现,有非并发实现和并发实现
递归
全排列问题,比如打印1-9的共9个字母的全排列。先输出1,然后是2-9的全排列,输出2,然后1-9中去除2的全排列。于是很自然想到递归的方法。写出伪代码:
permutaion(prefix, set) {
if set 为空
print prefix
for s in set:
permuetaion(prefix+s, set - s)
}
go递归实现
func permutaionImpl(prefix []byte, s []byte, cur int) {
if cur == len(s) {
fmt.Println(prefix)
return
}
for _, b := range s {
exist := false
for i := 0; i < cur; i++ {
if prefix[i] == b {
exist = true
break
}
}
if !exist {
prefix[cur] = b
permutaionImpl(prefix, s, cur+1)
}
}
}
func Permutation(s []byte) {
//前缀slice
p := make([]byte, len(s), len(s))
permutaionImpl(p, s, 0)
}
并发1
刚才实现的是 go 单线程执行的,改成并发版本的, 参考rob pike讲 Go Concurrency Patterns ,多个goroutine通过channel连接起来。goroutine1发送1给goroutine2, goroutine2发送12给goroutine3,goroutine3发送123给goroutine4, 以此类推。
func prefixIncrement(in []byte, s []byte, next chan []byte) {
for _, c := range s {
exist := false
for _, e := range in {
if e == c {
exist = true
break
}
}
if exist {
continue
}
temp := make([]byte, 0)
temp = append(temp, in...)
temp = append(temp, c)
next <- temp
}
}
func permutaionConImpl(req chan []byte, out chan []byte, s []byte) {
go func() {
//递归退出条件: len(v) == len(s)-1
v, ok := <-req
if !ok {
return
}
next := out
if len(v) != len(s)-1 {
next = make(chan []byte)
permutaionConImpl(next, out, s)
}
prefixIncrement(v, s, next)
for in := range req {
prefixIncrement(in, s, next)
}
close(next)
}()
}
// PermutationConcurrency 并发计算全排列
func PermutationConcurrency(s []byte) {
req, out := make(chan []byte), make(chan []byte)
//开启goroutine计算
permutaionConImpl(req, out, s)
over := make(chan struct{})
//要开goroutine读取out,如果放在主函数中,会导致死锁。
go func() {
for res := range out {
fmt.Println(res)
}
close(over)
}()
for _, c := range s {
sl := []byte{c}
req <- sl
}
close(req)
<-over
}
并发2
并发1中把每个排列的阶段拆分到不同的goroutine, 从goroutine1开始每个goroutine越来越繁忙,最后一个goroutine要输出n!个slice,任务轻重很不均衡。于是也可以考虑让每个goroutine做同样的事情,比如下面的实现
func PermutationConcurrencyVertical(s []byte) {
var sg sync.WaitGroup
for _, c := range s {
sg.Add(1)
//要传参数进去,避免只取到最后一个值
go func(k byte) {
p := make([]byte, len(s), len(s))
p[0] = k
permutaionImpl(p, s, 1)
defer sg.Done()
}(c)
}
sg.Wait()
}
代码地址
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入理解LINUX网络技术内幕
Christian Benvenuti / 夏安、闫江毓、黄景昌 / 中国电力出版社 / 2009-6 / 128.00元
Linux如此的流行正是得益于它的特性丰富及有效的网络协议栈。如果你曾经惊叹于Linux能够实现如此复杂的工作,或者你只是想通过现实中的例子学习现代网络,《深入理解Linux网络内幕》将会给你指导。同其他O'Reilly的流行书籍一样,《深入理解Linux网络内幕》清楚地阐述了网络的基本概念,并指导你如何用C语言实现。虽然早先的 TCP/IP经验是有用的,但初学者通过《深入理解Linux网络内幕》......一起来看看 《深入理解LINUX网络技术内幕》 这本书的介绍吧!