最悪の場合は線形時間の選択です.


このアルゴリズムは長い間書いています.ここでメモしてください.
アルゴリズムの原理は、中央値を分割要素として利用して第Mの小さい要素を選択し、中央値は自身に再帰して求める必要がある.アルゴリズムの最適化,平均化,最悪時間複雑度はO(N)であった.ランダムアルゴリズムに対して最悪時間複雑度が改善された.
ファーストクラスと同じpartitionを用いたが、このアルゴリズムで用いられているpivotは中央値であることを確認した.
コードバージョンはgolang 1.8.0です.
パスgoWorkSpace/algorithms/woselinear Select.go
package algorithms

import (
	"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 array
func getMidValueArray(array []int, startIndex, stopIndex int)(midValues []int) {
	array = array[startIndex : stopIndex]
	arrayGroups := len(array) / 5
	if len(array) % 5 == 0 {
		midValues = make([]int, arrayGroups)
	} else {
		midValues = make([]int, arrayGroups + 1)
	}
	//j := 0
	for 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 = -1
	for 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パッケージパスgoWork Space/golang Test/test.go、テストコードは以下の通りです.
package main

import (
	"fmt"
	"algorithms"
	"sort"
	"time"
	"math/rand"
)

func main() {

	//to new a random slice
	rand.Seed(time.Now().UnixNano())
	arrayLen := rand.Intn(400) + 200
	array := 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
", array) fmt.Println("rank", rank) fmt.Println("array length", arrayLen) //run the select function selectedValue := algorithms.WorseLinearSelect(array[:], 0, len(array), rank) sort.Ints(array[:]) fmt.Println("
selectedValue by sort", array[rank]) fmt.Println("
selectedValue", selectedValue) }
コードにはまだ小さな欠陥があり、partition法はスライスの再分割を必要としない部分に影響するが、アルゴリズムの複雑さに影響しない.
コードはすべてのテストケースに合格できます.