golang:插入已排序的切片

时间:2017-03-12 11:43:26

标签: go

将元素插入排序切片的最有效方法是什么?

我尝试了几件事,但最后都使用了至少2个附加内容,据我所知,这是一个新的切片副本

5 个答案:

答案 0 :(得分:5)

如果切片有足够的容量,则不需要新的副本。 插入位置后的元素可以向右移动。 只有当切片没有足够的容量时, 一个新的切片并复制所有值是必要的。

请注意,切片不是为快速插入而设计的。 因此,使用切片不会成为奇迹解决方案。 您可以创建自定义数据结构以提高效率, 但显然会有其他权衡因素。

在此过程中可以优化的一点是快速找到插入点。如果切片已排序,则可以使用二进制搜索在O(log n)时间内执行此操作。 但是,这可能并不重要, 考虑到复制切片末端的昂贵操作, 或在必要时重新分配。

答案 1 :(得分:0)

以下是如何插入排序后的字符串片段:

转到Playground链接至完整示例:https://play.golang.org/p/4RkVgEpKsWq

func Insert(ss []string, s string) []string {
    i := sort.SearchStrings(ss, s)
    ss = append(ss, "")
    copy(ss[i+1:], ss[i:])
    ss[i] = s
    return ss
}

答案 2 :(得分:0)

播放:https://play.golang.org/p/dUGmPurouxA

array1 := []int{1, 3, 4, 5}

    //want to insert at index 1
    insertAtIndex := 1
    temp := append([]int{}, array1[insertAtIndex:]...)
    array1 = append(array1[0:insertAtIndex], 2)
    array1 = append(array1, temp...)

    fmt.Println(array1)

答案 3 :(得分:0)

你可以使用堆:

package main

import (
   "container/heap"
   "sort"
)

type slice struct { sort.IntSlice }
func (s slice) Pop() interface{} { return 0 }

func (s *slice) Push(x interface{}) {
   (*s).IntSlice = append((*s).IntSlice, x.(int))
}

func main() {
   s := &slice{
      sort.IntSlice{11, 10, 14, 13},
   }
   heap.Init(s)
   heap.Push(s, 12)
   println(s.IntSlice[0] == 10)
}

注意堆不是严格排序的,但保证“最小元素” 成为第一个元素。我也没有在我的中实现 Pop 函数 例如,你会想要这样做。

https://golang.org/pkg/container/heap

答案 4 :(得分:0)

问题有两部分:找到插入值的位置和插入值。

使用 sort package 搜索函数通过二分搜索高效地找到插入索引。

使用一次对 append 的调用可以有效地将值插入到切片中:

// insertAt inserts v into s at index i and returns the new slice.
func insertAt(data []int, i int, v int) []int {
    if i == len(data) {
        // Insert at end is the easy case.
        return append(data, v)
    }

    // Make space for the inserted element by shifting
    // values at the insertion index up one index. The call
    // to append does not allocate memory when cap(data) is
    // greater ​than len(data).
    data = append(data[:i+1], data[i:]...)

    // Insert the new element.
    data[i] = v

    // Return the updated slice.
    return data
}

以下是在排序后的切片中插入值的代码:

func insertSorted(data []int, v int) []int {
    i := sort.Search(len(data), func(i int) bool { return data[i] >= v })
    return insertAt(data, i, v)
}

此答案中的代码使用了 int 的一部分。调整类型以匹配您的实际数据。

此答案中对 sort.Search 的调用可以替换为对辅助函数 sort.SearchInts 的调用。我在这个答案中显示 sort.Search 因为该函数适用于任何类型的切片。

如果不想添加重复值,请在插入前检查搜索索引处的值:

func insertSortedNoDups(data []int, v int) []int {
    i := sort.Search(len(data), func(i int) bool { return data[i] >= v })
    if i < len(data) && data[i] == v {
        return data
    }
    return insertAt(data, i, v)
}