当前位置: 首页 > 知识库问答 >
问题:

go - sort函数内的比较怎么优化?

何向荣
2024-06-03
// _sort 为参数sort.SliceStable(filedata, func(i, j int) bool {  if _sort == "name_desc" {    // 按拼音首字母z~a降序排列    return filedata[i].Pinyin[0] > filedata[j].Pinyin[0]  }  if _sort == "atime" {    // 升序, 从旧到新    return filedata[i].Timestamp.Atime < filedata[j].Timestamp.Atime  }  if _sort == "atime_desc" {    // 降序, 从新到旧    return filedata[i].Timestamp.Atime > filedata[j].Timestamp.Atime  }  if _sort == "mtime" {    // 升序, 从旧到新    return filedata[i].Timestamp.Mtime < filedata[j].Timestamp.Mtime  }  if _sort == "mtime_desc" {    // 降序, 从新到旧    return filedata[i].Timestamp.Mtime > filedata[j].Timestamp.Mtime  }  if _sort == "ctime" {    // 升序, 从旧到新    return filedata[i].Timestamp.Ctime < filedata[j].Timestamp.Ctime  }  if _sort == "ctime_desc" {    // 降序, 从新到旧    return filedata[i].Timestamp.Ctime > filedata[j].Timestamp.Ctime  }  // 按拼音首字母a~z升序排列, 默认  return filedata[i].Pinyin[0] < filedata[j].Pinyin[0]  })

这个看着挺丑,但好像没啥有意义的优化方案,看网上的一些方案,纯粹就是挪了个窝,没啥意义吧?

共有2个答案

汪凌
2024-06-03

sort 函数(无论是在 C++ 的 STL(Standard Template Library)中,还是在其他编程语言的标准库中)通常允许你提供一个自定义的比较函数或函数对象(通常称为比较器或谓词),以便定义排序的顺序。优化 sort 函数内的比较通常取决于几个因素,包括你的数据特性、比较器的实现以及你正在使用的排序算法的实现。

以下是一些建议,可以帮助你优化 sort 函数内的比较:

减少比较次数:    如果可能的话,尽量减少比较的次数。例如,如果你知道数据已经部分排序,或者你可以利用某些特性来避免不必要的比较,那么就可以减少比较次数。优化比较器的实现:    确保你的比较器尽可能地高效。避免在比较器中进行复杂的计算或内存分配。    如果你的比较器依赖于外部数据或状态,确保这些数据或状态在排序过程中是稳定的,并且它们的访问是高效的。选择适当的排序算法:    虽然大多数标准库实现都会自动选择一种高效的排序算法(如快速排序、归并排序或堆排序),但了解你正在使用的算法的特性仍然是有帮助的。    对于某些特殊类型的数据(如已排序或接近排序的数据),某些算法可能会比其他算法更快。利用数据特性:    如果你的数据具有某些特定特性(如范围限制、可预测的模式等),那么你可能可以利用这些特性来优化排序过程。    例如,如果你知道数据中的元素都在一个很小的范围内,那么你可以使用计数排序或桶排序等线性时间复杂度的排序算法。并行化排序:    如果你的处理器支持并行计算,并且你的数据量大到足以从并行化中受益,那么你可以考虑使用并行排序算法。这通常需要在比较器中注意线程安全性。使用稳定的排序算法:    如果你的数据包含相等的元素,并且你需要保持它们的相对顺序(即稳定的排序),那么确保你使用的排序算法是稳定的。避免不必要的内存分配:    如果你的比较器涉及到动态内存分配(如使用 new 或 malloc),那么这可能会成为性能瓶颈。考虑使用静态分配、栈分配或对象池来减少内存分配的开销。使用编译器优化:    确保你的编译器启用了优化选项(如 -O2 或 -O3 在 GCC 和 Clang 中)。这些选项可以帮助编译器自动进行各种优化,包括针对 sort 函数的优化。分析性能瓶颈:    使用性能分析工具(如 gprof、Valgrind 的 Helgrind 工具、Intel VTune Amplifier 等)来确定 sort 函数中的性能瓶颈。这可以帮助你确定是否需要进一步优化比较器或其他部分的代码。简化数据结构:    如果可能的话,简化你的数据结构以减少比较的开销。例如,如果你正在对复杂对象进行排序,并且这些对象包含许多不必要的字段,那么考虑只包含用于排序的字段的简化版本的对象。
水飞掣
2024-06-03

你的sort.SliceStable函数中的比较逻辑已经比较清晰,针对每一种排序类型都有相应的处理。确实,如果每一种排序逻辑都很简单且直接,那么很难在这个基础上进行有意义的优化。

然而,有一些方法可以使代码更整洁,即使它们可能不会显著提高性能。这可以提高代码的可读性和可维护性。

以下是一些可能的改进建议:

  1. 使用switch语句:将多个if-else语句替换为switch语句可以使代码看起来更整洁。
  2. 提取比较函数:将每种排序类型的比较逻辑提取到单独的函数中,可以使主函数更简洁,并且更容易理解每个排序类型是如何工作的。
  3. 避免重复的代码:如果某些比较逻辑是重复的(例如升序和降序的比较),可以考虑通过传递一个额外的参数来指示是升序还是降序,从而避免重复的代码。

以下是根据这些建议修改后的代码示例:

func compareByName(i, j int, desc bool) bool {    if desc {        return filedata[i].Pinyin[0] > filedata[j].Pinyin[0]    }    return filedata[i].Pinyin[0] < filedata[j].Pinyin[0]}func compareByTime(i, j int, desc bool, getTime func(item TypeOfItem) time.Time) bool {    if desc {        return getTime(filedata[i]) > getTime(filedata[j])    }    return getTime(filedata[i]) < getTime(filedata[j])}// 在主函数中switch _sort {case "name_desc":    sort.SliceStable(filedata, func(i, j int) bool {        return compareByName(i, j, true)    })case "atime":    sort.SliceStable(filedata, func(i, j int) bool {        return compareByTime(i, j, false, func(item TypeOfItem) time.Time { return item.Timestamp.Atime })    })case "atime_desc":    sort.SliceStable(filedata, func(i, j int) bool {        return compareByTime(i, j, true, func(item TypeOfItem) time.Time { return item.Timestamp.Atime })    })// 其他情况类似...default:    sort.SliceStable(filedata, func(i, j int) bool {        return compareByName(i, j, false)    })}

注意,这里的TypeOfItem应该替换为你的filedata切片的元素类型。同时,我假设Timestamp.AtimeTimestamp.MtimeTimestamp.Ctime都是time.Time类型。

这样的代码结构更清晰,每种排序逻辑都被封装在单独的函数中,主函数只需要根据_sort的值调用相应的函数即可。同时,通过传递额外的参数,我们避免了在升序和降序比较之间的重复代码。

然而,需要强调的是,这样的代码重构主要是为了提高代码的可读性和可维护性,而不是为了提高性能。在大多数情况下,Go语言的编译器已经对这样的比较逻辑进行了优化,因此你不太可能看到明显的性能提升。如果你真的需要提高性能,那么可能需要从其他方面入手,例如减少内存分配、避免不必要的复制等。

 类似资料:
  • 我正在阅读每个程序员都应该知道的内存https://people.freebsd.org/~lstewart/articles/cpumemory.pdf,它说内联函数使你的代码更可优化 例如 :特别是函数的内联允许编译器一次优化更大的代码块,这反过来又可以生成机器代码,从而更好地利用处理器的管道架构。 and: 当程序的较大部分可以被视为单个单元时,代码和数据的处理(通过死代码消除或值范围传播等

  • 问题内容: 比较运算符的 “ Go编程语言规范”部分使我相信,仅包含可比较字段的结构应具有可比性: 如果结构的所有字段都是可比较的,则它们的值是可比较的。如果两个结构值对应的非空白字段相等,则它们相等。 这样,由于“ Student”结构中的所有字段都是可比较的,因此我希望编译以下代码: 但是,它无法使用以下消息进行编译: 无效的操作:alice> = carol(运算符> =未在结构上定义) 我

  • 过滤出数组中比较函数不返回 true 的所有值。 类似于difference ,除了接受一个 comparator (比较函数)。 使用 Array.filter() 和 Array.findIndex() 来查找合适的值。 const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b

  • 比较函数是一个函数,它接受两个参数a和b,并返回一个描述其顺序的整数。如果a小于b,则结果为负整数。如果a大于b,则结果为某个正整数。否则,a和b相等,结果为零。 此函数通常用于参数化来自标准库的排序和搜索算法。 实现字符的比较功能相当容易;只需减去参数: 这是因为通常假设两个字符之间的差适合一个整数。(注意,此假设不适用于的系统) 这种技巧无法用于比较整数,因为两个整数之间的差通常不适合一个整数

  • 问题内容: 这怎么不出现属性错误?函数对象没有任何比较方法。它以某种方式使用id()吗? 我知道它比较地址,但是如何?拦截__lt , eq__等是一些低级黑客吗? 问题答案: 函数对象没有定义自己的比较或丰富的比较。相反,它们从类型对象继承,这些类型对象根据内存中的对象地址实现丰富的比较。 因此,是的,它像内置的id()函数一样有效地使用地址。 在Python 3中,功能不再可排序。

  • 在C Sort函数中,第三个可选参数是用于对对象进行排序的比较器。如果我们传入的比较器更少,我们将以递增的顺序获得对象。(如果比较器的评估结果为真,则不会更改位置,否则将对元素进行交换!)我的理解正确吗? 按照同样的方式,如果我们将一个较少的比较器传递给优先级队列,我们应该得到一个最小堆(如果基础数据结构被选择为向量,对象将按递增顺序排序)。如果我们调用top(),将返回向量的第一个元素,这是最小