详解Go语言如何实现字符串切片反转函数

2022-10-19 18:23:01
目录
Python 中的 reverse 函数实现一个 reverse 反转函数利用两个切片实现前后两两原地交换反转为原切片的副本总结

Python>

Go 语言不像其他语言如 Python,有着内置的 reverse() 函数,先来看一下 Python 中对于列表的反转方法,然后我们再来学习如果在 Go 语言中实现相同的功能。

>>> myList = [2022, 2021, 2008, 2012]
>>> myList.reverse()
>>> print("Reversed List:", myList)
Reversed List: [2012, 2008, 2021, 2022]
>>> 

实现一个>

reverse 算法取一个数据集,并将该数据集的值进行反转,Go 标准的 sort 包并没有内置的方法来反转一个切片。

利用两个切片实现

设计思想:

    确定切片长度获取最后一个元素以相反的顺序在新切片中添加最后一个元素到第一个位置
    package main
    
    import "fmt"
    
    func main() {
        s := []string{"hello", "foo", "bar", "go", "abc", "zzz"}
    
        // 定义新的反转切片
        reverseOfS := []string{}
    
        // 遍历原切片 s
        for i := range s {
            reverseOfS = append(reverseOfS, s[len(s)-1-i])
        }
        fmt.Println(reverseOfS)
    }

    运行结果:

    [zzz abc go bar foo hello]

    显然,这种方式会额外花费一个相同空间的切片,空间复杂度为 O(n)

    前后两两原地交换

    我们可以写一个简易的>reverse 函数来进行数据的反转,通过循环原切片的一半,然后依次与对应的元素进行交换,比如::

    func reverse(s []string) []string {
        for i := 0; i < len(s)/2; i++ {
            j := len(s) - i - 1
            s[i], s[j] = s[j], s[i]
        }
        return  s
    }

    这个函数可以通过更简短的实现,通过 Go 内部的操作进行循环:

    package main
    
    import "fmt"
    
    func reverse(s []string) []string {
        for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
            s[i], s[j] = s[j], s[i]
        }
        return s
    }
    
    func main() {
        s := []string{"hello", "foo", "bar", "go", "abc", "zzz"}
    
        reverseOfS := reverse(s)
    
        fmt.Println(reverseOfS)
    }
    

    执行结果:

    [zzz abc go bar foo hello]

    但是,上面的 reverse 函数都是通过切片按值传递,其实我们在修改传递中的 []string 切片,实际上,可以通过以下方式进一步简写:

    package main
    
    import "fmt"
    
    func reverse(s []string) {
        for i := 0; i < len(s)/2; i++ {
            j := len(s) - i - 1
            s[i], s[j] = s[j], s[i]
        }
    }
    
    func main() {
        s := []string{"hello", "foo", "bar", "go", "abc", "zzz"}
    
        reverse(s)
        fmt.Printf("%v\n", s)
    }

    此时,reverse() 函数不会返回切片的另一个引用,此时的交换就是就地进行,此时更像文章开头 Python 中的 reverse() 函数。

    反转为原切片的副本

    如果我们要返回切片的反转的副本,reverse>

    package main
    
    import "fmt"
    
    func reverse(s []string) []string {
    
        newS := make([]string, len(s))
        for i, j := 0, len(s)-1; i <= j; i, j = i+1, j-1 {
            newS[i], newS[j] = s[j], s[i]
        }
        return newS
    }
    
    func main() {
        s := []string{"hello", "foo", "bar", "go", "abc", "zzz"}
    
        fmt.Printf("原字符串切片:%v\n", s)
        fmt.Printf("反转后的切片:%v\n", reverse(s))
    }

    运行结果:

    原字符串切片:[hello foo bar go abc zzz]
    反转后的切片:[zzz abc go bar foo hello]

    可以看到,原切片是没有变化的。

    当然,因为我们没有就地修改原切片,因此又可以回到最初的方法 append,看代码:

    func reverse(s []string) []string {
    
        newS := make([]string, 0, len(s))
    
        for i := len(s)-1; i >= 0; i-- {
            newS = append(newS, s[i])
        }
        return newS
    }

    运行结果图如下:

    总结

    本文通过>reverse() 函数的一个示例,引发出一个思考:Go 语言中有没有类似的反转函数?

    然后通过几种方式实现同样的字符串切片的反转功能,并通过借助额外空间和就地反转两种方式实现了功能相同 reverse 函数,其实类似的反转思想也可以用于字符串或者链表反转等其他数据结构。

    到此这篇关于详解Go语言如何实现字符串切片反转函数的文章就介绍到这了,更多相关Go语言字符串切片反转函数内容请搜索易采站长站以前的文章或继续浏览下面的相关文章希望大家以后多多支持易采站长站!