最差情况为线性时间的选择

来源:互联网 发布:淘宝开店宝软件 编辑:程序博客网 时间:2024/05/30 20:09

这个算法写了我好久,在这里记一下。

算法的原理是利用中位数来作为划分元素选择第M小的元素,中位数需要递归自身来求得。算法的最优,平均,最差时间复杂度都为O(N)。相对于随机算法改善了最差时间复杂度。

和快排用了同样的partition,但是这个算法所使用的pivot是确定的,即中位数。

代码版本为golang 1.8.0。

路径goWorkSpace/algorithms/worseLinearSelect.go

package algorithmsimport ("fmt")func WorseLinearSelect(array []int, startIndex, stopIndex, rank int)(selectedValue int) {if startIndex + 5 > stopIndex {insertionSort(array)return array[rank]}midValueArrays := getMidValueArray(array, startIndex, stopIndex)midValue := WorseLinearSelect(midValueArrays, 0, len(midValueArrays), (len(midValueArrays) - 1)/2)devideIndex := partitionWithPiovt(array, midValue)if devideIndex == rank {return array[devideIndex]} else if devideIndex > rank {return WorseLinearSelect(array, startIndex, devideIndex, rank)} else {return WorseLinearSelect(array, devideIndex + 1, stopIndex, rank)}}//sort array by groups and return the mid value arrayfunc getMidValueArray(array []int, startIndex, stopIndex int)(midValues []int) {array = array[startIndex : stopIndex]arrayGroups := len(array) / 5if len(array) % 5 == 0 {midValues = make([]int, arrayGroups)} else {midValues = make([]int, arrayGroups + 1)}//j := 0for i, j := 0, 0; i < len(array); i += 5 {if i + 5 <= len(array) {b := array[i : i + 5]insertionSort(b)midValues[j] = array[i + 2]} else {insertionSort(array[i : len(array)])midValues[j] = array[(i + len(array)) / 2]}//(i + 5 <= len(array)) ? (insertionSort(array[i : i + 5])) : (insertionSort(array[i : len(array)]))j ++}return midValues}func partitionWithPiovt(array []int, pivotValue int)(firstIndex int) {firstIndex = -1for secondIndex := 0; secondIndex != len(array); secondIndex ++ {if array[secondIndex] < pivotValue {firstIndex ++swap(&array[firstIndex], &array[secondIndex])} else if array[secondIndex] == pivotValue {firstIndex ++swap(&array[firstIndex], &array[secondIndex])swap(&array[0], &array[firstIndex])}}swap(&array[0], &array[firstIndex])return firstIndex}func insertionSort(array []int) {defer func() {if r := recover(); r != nil {fmt.Println(r)}}()for i := 1; i != len(array); i++ {selectValue := array[i]for j := i - 1; j >= 0; j -- {if array[j] > selectValue {swap(&array[j], &array[j + 1])} else {break}}}}func swap(a *int, b *int) {temp := *b*b = *a*a = temp}func Partition(array []int, pivotValue int) int {return partitionWithPiovt(array, pivotValue)}


main包路径goWorkSpace/golangTest/test.go,测试代码如下:

package mainimport ("fmt""algorithms""sort""time""math/rand")func main() {//to new a random slicerand.Seed(time.Now().UnixNano())arrayLen := rand.Intn(400) + 200array := make([]int, arrayLen)for index, _ := range array {array[index] = rand.Intn(5 * arrayLen)fmt.Print(",", array[index])}rank := rand.Intn(arrayLen)fmt.Println("array befor select\n", array)fmt.Println("rank", rank)fmt.Println("array length", arrayLen)//run the select functionselectedValue := algorithms.WorseLinearSelect(array[:], 0, len(array), rank)sort.Ints(array[:])fmt.Println("\nselectedValue by sort", array[rank])fmt.Println("\nselectedValue", selectedValue)}

后来发现代码还有小缺陷,partition方法会影响到切片中不需要重新划分的部分,但不影响算法的复杂度,只是多了一点无意义的操作。

代码对于所有测试用例都能通过。

                                             
0 0
原创粉丝点击