在Go语言中实现的归并排序算法中遇到了问题,无法找到错误。

huangapple go评论79阅读模式
英文:

Trouble finding bug in the merge sort algorithm implemented in Go

问题

我想实现一个归并排序算法,但是在找出程序为什么无法正确排序方面遇到了困难。我尝试向ChatGPT寻求一些建议,但它无法帮助找出错误所在。

package main

import (
	"fmt"
	"sort"
)

// sortable是必须由类型实现的接口,以便通过归并排序进行排序。
type sortable interface {
	sort.Interface
	Set(i int, x any)
	At(i int) any
}

// IntSlice将sortable的方法附加到[]int,以升序排序。
type IntSlice []int

func (x IntSlice) Len() int           { return len(x) }
func (x IntSlice) Less(i, j int) bool { return x[i] <= x[j] } // 实际上表示`<=`运算符
func (x IntSlice) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
func (x IntSlice) Set(i int, a any)   { x[i] = a.(int) }
func (x IntSlice) At(i int) any       { return x[i] }

// 将两个数组合并为一个
func merge(data sortable, lo, mid, hi int) {
	temp := make([]any, hi-lo+1)
	for i := lo; i <= hi; i++ {
		temp[i-lo] = data.At(i)
	}
	i, j := lo, mid+1
	for k := lo; k <= hi; k++ {
		if i > mid {
			data.Set(k, temp[j-lo])
			j++
		} else if j > hi {
			data.Set(k, temp[i-lo])
			i++
		} else if data.Less(i, j) { // 实际上表示`<=`运算符
			data.Set(k, temp[i-lo])
			i++
		} else {
			data.Set(k, temp[j-lo])
			j++
		}
	}
}

// 递归解决方法
func mergeSort(data sortable, lo, hi int) {
	if hi-lo > 1 {
		mid := (lo + hi) / 2
		mergeSort(data, lo, mid)
		mergeSort(data, mid+1, hi)
		merge(data, lo, mid, hi)
	} else {
		if !data.Less(lo, hi) { // 实际上表示`>`运算符
			data.Swap(lo, hi)
		}
	}
}

func SortTtE(data sortable) {
	mergeSort(data, 0, data.Len()-1)
}

func main() {
	a := []int{10, 9, 11, 2, 7, 9, 6}
	SortTtE(IntSlice(a))
	fmt.Println(a)
	// 错误的输出: [2 6 9 7 10 11 9]
}

可能是因为我在控制流程中犯了错误,所以我希望有人能帮助我找出错误所在。
这是playground的链接: https://go.dev/play/p/AXZqZH2Ko1E

英文:

I want to implement a merge sort algorithm but was stuck in finding why my program fails to do the right sorting. I had tried to ask ChatGPT for some suggestions on it, but it couldn't help find where the bug is.

package main

import (
	&quot;fmt&quot;
	&quot;sort&quot;
)

// sortable is the interface that must be implemented by a type to be sorted by the merge sort.
type sortable interface {
	sort.Interface
	Set(i int, x any)
	At(i int) any
}

// IntSlice attaches the methods of sortable to []int, sorting in increasing order.
type IntSlice []int

func (x IntSlice) Len() int           { return len(x) }
func (x IntSlice) Less(i, j int) bool { return x[i] &lt;= x[j] } // actually represents the `&lt;=` operator
func (x IntSlice) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
func (x IntSlice) Set(i int, a any)   { x[i] = a.(int) }
func (x IntSlice) At(i int) any       { return x[i] }

// merge two arrays into one
func merge(data sortable, lo, mid, hi int) {
	temp := make([]any, hi-lo+1)
	for i := lo; i &lt;= hi; i++ {
		temp[i-lo] = data.At(i)
	}
	i, j := lo, mid+1
	for k := lo; k &lt;= hi; k++ {
		if i &gt; mid {
			data.Set(k, temp[j-lo])
			j++
		} else if j &gt; hi {
			data.Set(k, temp[i-lo])
			i++
		} else if data.Less(i, j) { // actually represents the `&lt;=` operator
			data.Set(k, temp[i-lo])
			i++
		} else {
			data.Set(k, temp[j-lo])
			j++
		}
	}
}
// recursive solving method
func mergeSort(data sortable, lo, hi int) {
	if hi-lo &gt; 1 {
		mid := (lo + hi) / 2
		mergeSort(data, lo, mid)
		mergeSort(data, mid+1, hi)
		merge(data, lo, mid, hi)
	} else {
		if !data.Less(lo, hi) { // actually represents the `&gt;` operator
			data.Swap(lo, hi)
		}
	}
}

func SortTtE(data sortable) {
	mergeSort(data, 0, data.Len()-1)
}

func main() {
	a := []int{10, 9, 11, 2, 7, 9, 6}
	SortTtE(IntSlice(a))
	fmt.Println(a)
// the false output: [2 6 9 7 10 11 9]
}

It might because I made mistakes in my control flow, so I was expecting someone to help me find where the bug is.
This is where the playground is: https://go.dev/play/p/AXZqZH2Ko1E

答案1

得分: 1

merge函数中,你在检查data.Less的同时修改了数组data,这会导致一个未定义的状态,因为此时你的实际数据存储在temp中。

为了解决这个问题,应该在temp上进行检查。

func merge(data sortable, lo, mid, hi int) {
	temp := make([]int, hi-lo+1)
	for i := lo; i <= hi; i++ {
        // 注意,我在这里必须进行类型转换,因为temp是[]int类型,
        // 而data是一个接口
		temp[i-lo] = data.At(i).(int)
	}
	i, j := lo, mid+1
	for k := lo; k <= hi; k++ {
		if i > mid {
			data.Set(k, temp[j-lo])
			j++
		} else if j > hi {
			data.Set(k, temp[i-lo])
			i++
		} else if temp[i-lo] <= temp[j-lo] { // <- 在这里,对实际数据进行检查
			data.Set(k, temp[i-lo])
			i++
		} else {
			data.Set(k, temp[j-lo])
			j++
		}
	}
}

英文:

In merge, you are modifying the array data at the same time you are checking for data.Less. This leads to an undefined state, because your actual data is stored in temp at that moment.

To fix this, perform the check on temp

func merge(data sortable, lo, mid, hi int) {
	temp := make([]int, hi-lo+1)
	for i := lo; i &lt;= hi; i++ {
        // Notice I have to cast here, because temp it []int, 
        // but data is an interface
		temp[i-lo] = data.At(i).(int)
	}
	i, j := lo, mid+1
	for k := lo; k &lt;= hi; k++ {
		if i &gt; mid {
			data.Set(k, temp[j-lo])
			j++
		} else if j &gt; hi {
			data.Set(k, temp[i-lo])
			i++
		} else if temp[i-lo] &lt;= temp[j-lo] { // &lt;- here, check against the actual data
			data.Set(k, temp[i-lo])
			i++
		} else {
			data.Set(k, temp[j-lo])
			j++
		}
	}
}

huangapple
  • 本文由 发表于 2023年3月22日 19:33:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75811731.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定