feat(Go-Tool):新增二分法查找算法及其单测、插入查询及其单测、lomuto划分查询第k小元素及其单测、归并排序及其单测、快速排序及其单测.
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/8/18 17:45
|
||||
* @Description:二分查找法,对于有序数组进行查找
|
||||
*/
|
||||
|
||||
package search
|
||||
|
||||
func BinarySearch(list []int, value int) int {
|
||||
low := 0
|
||||
high := len(list) - 1
|
||||
var mid int
|
||||
|
||||
for low <= high {
|
||||
mid = (low + high) >> 1 //相当于(low + high) / 2
|
||||
if value == list[mid] {
|
||||
return mid
|
||||
}
|
||||
|
||||
if value < list[mid] {
|
||||
high = mid - 1
|
||||
} else {
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/8/18 17:59
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package search
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
|
||||
evenNumList := []int{1, 2, 3, 5, 6, 7, 9, 10, 22, 111, 333, 431}
|
||||
|
||||
for _, r := range evenNumList {
|
||||
position := BinarySearch(evenNumList, r)
|
||||
fmt.Println(position)
|
||||
}
|
||||
|
||||
position := BinarySearch(evenNumList, 999)
|
||||
fmt.Println(position)
|
||||
|
||||
position = BinarySearch(evenNumList, -10)
|
||||
fmt.Println(position)
|
||||
|
||||
fmt.Println()
|
||||
|
||||
oddNumList := []int{1, 2, 3, 5, 6, 7, 9, 10, 22, 111, 333, 431, 3211}
|
||||
for _, r := range oddNumList {
|
||||
position := BinarySearch(oddNumList, r)
|
||||
fmt.Println(position)
|
||||
}
|
||||
|
||||
position = BinarySearch(oddNumList, 999)
|
||||
fmt.Println(position)
|
||||
|
||||
position = BinarySearch(oddNumList, -10)
|
||||
fmt.Println(position)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/8/19 10:24
|
||||
* @Description:
|
||||
*
|
||||
*/
|
||||
|
||||
package search
|
||||
|
||||
func InsertionSearch(list []int, value int) int {
|
||||
low := 0
|
||||
high := len(list) - 1
|
||||
var mid int
|
||||
|
||||
//插值查找这边如果数字和起始数字差别大的话,计算出来的下标会越界挺多的
|
||||
if value > list[high-1] || value < list[0] {
|
||||
return -1
|
||||
}
|
||||
|
||||
for low < high {
|
||||
mid = low + (high-low)*(value-list[low])/(list[high]-list[low])
|
||||
if value == list[mid] {
|
||||
return mid
|
||||
}
|
||||
|
||||
if value < list[mid] {
|
||||
high = mid - 1
|
||||
} else {
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
从折半查找中可以看出,折半查找的查找效率还是不错的。可是为什么要折半呢?为什么不是四分之一、八分之一呢?打个比方,在牛津词典里要查找“apple”这个单词,会首先翻开字典的中间部分,然后继续折半吗?
|
||||
肯定不会,对于查找单词“apple”,我们肯定是下意识的往字典的最前部分翻去,而查找单词“zero”则相反,我们会下意识的往字典的最后部分翻去。
|
||||
所以在折半查找法的基础上进行改造就出现了插值查找法,也叫做按比例查找。所以插值查找与折半查找唯一不同的是在于mid的计算方式上,它的计算方式为:
|
||||
|
||||
mid = low + (high - low) * (searchValue - data[low]) / (data[high] - data[low])
|
||||
|
||||
插值查找的时间复杂度也是O(log2n),但是对于数据集合较长,且关键字分布比较均匀的数据集合来说,插值查找的算法性能比折半查找要好,其它的则不适用。
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/8/19 10:38
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package search
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInsertionSearch(t *testing.T) {
|
||||
|
||||
evenNumList := []int{1, 2, 3, 5, 6, 7, 9, 10, 22, 111, 333, 431}
|
||||
|
||||
for _, r := range evenNumList {
|
||||
position := InsertionSearch(evenNumList, r)
|
||||
fmt.Println(position)
|
||||
}
|
||||
|
||||
position := InsertionSearch(evenNumList, 999)
|
||||
fmt.Println(position)
|
||||
|
||||
position = InsertionSearch(evenNumList, -10)
|
||||
fmt.Println(position)
|
||||
|
||||
fmt.Println()
|
||||
|
||||
oddNumList := []int{1, 2, 3, 5, 6, 7, 9, 10, 22, 111, 333, 431, 3211}
|
||||
for _, r := range oddNumList {
|
||||
position := InsertionSearch(oddNumList, r)
|
||||
fmt.Println(position)
|
||||
}
|
||||
|
||||
position = InsertionSearch(oddNumList, 999)
|
||||
fmt.Println(position)
|
||||
|
||||
position = InsertionSearch(oddNumList, -10)
|
||||
fmt.Println(position)
|
||||
}
|
||||
@@ -11,7 +11,7 @@ package search
|
||||
//start : 开始比较的数字下标
|
||||
//end :结束比较的数字下标
|
||||
//作用说明:
|
||||
func partition(list []int, start int, end int) int {
|
||||
func LomutoPartition(list []int, start int, end int) int {
|
||||
moveSubscript := start
|
||||
compareValue := list[start]
|
||||
for i := start + 1; i <= end; i++ {
|
||||
@@ -27,13 +27,13 @@ func partition(list []int, start int, end int) int {
|
||||
func LomutoQuiteSelect(list []int, pointPosition int) int {
|
||||
positionCheck(pointPosition, len(list)) //下标校验
|
||||
|
||||
nowPosition := partition(list, 0, len(list)-1)
|
||||
nowPosition := LomutoPartition(list, 0, len(list)-1)
|
||||
//循环进行lomuto划分处理,知道找到我们需要的那个位置的元素
|
||||
for nowPosition != pointPosition-1 {
|
||||
if nowPosition > pointPosition-1 {
|
||||
nowPosition = partition(list, 0, nowPosition)
|
||||
nowPosition = LomutoPartition(list, 0, nowPosition)
|
||||
} else {
|
||||
nowPosition = partition(list, nowPosition+1, len(list)-1)
|
||||
nowPosition = LomutoPartition(list, nowPosition+1, len(list)-1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@ import (
|
||||
|
||||
func TestPartition(t *testing.T) {
|
||||
list := []int{99, 1, 2, 3, 4, 100, 200, 90, 5}
|
||||
s := partition(list, 0, 9-1)
|
||||
s := LomutoPartition(list, 0, 9-1)
|
||||
fmt.Println(fmt.Sprintf("当前第一个元素应该存在位置为:%d", s))
|
||||
for _, r := range list {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
|
||||
s = partition(list, 0, 9-1)
|
||||
s = LomutoPartition(list, 0, 9-1)
|
||||
fmt.Println(fmt.Sprintf("当前第一个元素应该存在位置为:%d", s))
|
||||
for _, r := range list {
|
||||
fmt.Print(r, " ")
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/8/19 11:44
|
||||
* @Description:这边提供一个递归的归并排序算法,非递归的理解成本比较高,并且还有多路归并排序,需要理解对应概念
|
||||
* 最坏时间复杂度O(nlogn) 最好时间复杂度O(logn) 空间复杂度O(n)
|
||||
*/
|
||||
|
||||
package sort
|
||||
|
||||
func MergeSort(list []int) {
|
||||
middle := len(list) / 2
|
||||
leftList := copyList(list, 0, middle)
|
||||
rightList := copyList(list, middle, len(list))
|
||||
if len(list) > 1 {
|
||||
MergeSort(leftList) //先对左边进行归并排序
|
||||
MergeSort(rightList) //再对右边进行归并排序
|
||||
mergeAll(list, leftList, rightList) //对左右排序的结果进行组合
|
||||
}
|
||||
}
|
||||
|
||||
func copyList(list []int, start int, end int) []int {
|
||||
result := make([]int, 0)
|
||||
for i := start; i < end; i++ {
|
||||
result = append(result, list[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func mergeAll(array []int, left []int, right []int) {
|
||||
l, r, i := 0, 0, 0 //左数组的下标、右数组的下标、组合数组的下标
|
||||
for l < len(left) && r < len(right) {
|
||||
if left[l] > right[r] {
|
||||
array[i] = right[r]
|
||||
i++
|
||||
r++
|
||||
} else {
|
||||
array[i] = left[l]
|
||||
i++
|
||||
l++
|
||||
}
|
||||
}
|
||||
|
||||
for r < len(right) {
|
||||
array[i] = right[r]
|
||||
r++
|
||||
i++
|
||||
}
|
||||
|
||||
for l < len(left) {
|
||||
array[i] = left[l]
|
||||
l++
|
||||
i++
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/8/19 11:45
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package sort
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMergeSort(t *testing.T) {
|
||||
list1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
MergeSort(list1)
|
||||
for _, r := range list1 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list2 := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
|
||||
MergeSort(list2)
|
||||
for _, r := range list2 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list3 := []int{100, 5, 222, 312, 552, 354, 8, 21, 90, 2, 0, 12, 345, 67}
|
||||
MergeSort(list3)
|
||||
for _, r := range list3 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list4 := []int{1, 19, 42, 7, 3131, 44, 56, 123, 589, 21, 975, 123, 5467, 143, 7, 321, 77, 3}
|
||||
MergeSort(list4)
|
||||
for _, r := range list4 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/8/19 17:06
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package sort
|
||||
|
||||
import "Go-Tool/util/search"
|
||||
|
||||
//通过hoare划分来实现快速排序
|
||||
func QuickSort(list []int, start, end int) {
|
||||
if start < end {
|
||||
position := hoarePartition(list, start, end)
|
||||
QuickSort(list, start, position) //注意这边结束的下表是position,而不是position + 1
|
||||
QuickSort(list, position+1, end)
|
||||
}
|
||||
}
|
||||
|
||||
//通过lomuto划分来实现快速排序
|
||||
func QuickSort1(list []int, start, end int) {
|
||||
if start < end {
|
||||
position := search.LomutoPartition(list, start, end)
|
||||
QuickSort(list, start, position)
|
||||
QuickSort(list, position+1, end)
|
||||
}
|
||||
}
|
||||
|
||||
func hoarePartition(list []int, start int, end int) int {
|
||||
value := list[start] //比较的元素
|
||||
s := start
|
||||
e := end
|
||||
for s < e {
|
||||
//找到数组终止前,比目标数(value)大的数字
|
||||
for ; s < end && list[s] < value; s++ {
|
||||
}
|
||||
//找到数组结束前,比目标数(value)小的数字
|
||||
for ; e > start && list[e] >= value; e-- {
|
||||
}
|
||||
if s < e {
|
||||
list[s], list[e] = list[e], list[s]
|
||||
}
|
||||
}
|
||||
list[start], list[e] = list[e], list[start]
|
||||
return e
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/8/19 17:57
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package sort
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQuickSort(t *testing.T) {
|
||||
list := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
QuickSort(list, 0, len(list)-1)
|
||||
|
||||
for _, r := range list {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list1 := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
|
||||
QuickSort(list1, 0, len(list1)-1)
|
||||
|
||||
for _, r := range list1 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list2 := []int{432, 412, 213, 456, 7, 213, 4, 78, 13, 87, 312321, 456, 7, 231, 234, 3}
|
||||
QuickSort(list2, 0, len(list2)-1)
|
||||
|
||||
for _, r := range list2 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list3 := []int{1, 312, 356, 76, 2, 54, 78, 321, 3455, 65732, 123534, 54351, 4213, 123, 56, 6, 732, 123, 44, 51, 5, 61, 543}
|
||||
QuickSort(list3, 0, len(list3)-1)
|
||||
|
||||
for _, r := range list3 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func TestQuickSort1(t *testing.T) {
|
||||
list := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
QuickSort1(list, 0, len(list)-1)
|
||||
|
||||
for _, r := range list {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list1 := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
|
||||
QuickSort1(list1, 0, len(list1)-1)
|
||||
|
||||
for _, r := range list1 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list2 := []int{432, 412, 213, 456, 7, 213, 4, 78, 13, 87, 312321, 456, 7, 231, 234, 3}
|
||||
QuickSort1(list2, 0, len(list2)-1)
|
||||
|
||||
for _, r := range list2 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
list3 := []int{1, 312, 356, 76, 2, 54, 78, 321, 3455, 65732, 123534, 54351, 4213, 123, 56, 6, 732, 123, 44, 51, 5, 61, 543}
|
||||
QuickSort1(list3, 0, len(list3)-1)
|
||||
|
||||
for _, r := range list3 {
|
||||
fmt.Print(r, " ")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
Reference in New Issue
Block a user