前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2021-01-14:timsort是什么,如何用代码实现?

2021-01-14:timsort是什么,如何用代码实现?

原创
作者头像
福大大架构师每日一题
修改于 2021-01-15 02:48:41
修改于 2021-01-15 02:48:41
1.1K0
举报

福哥答案2021-01-14:

答案来自此链接:

介绍:

timsort是一种混合、稳定高效的排序算法,源自合并排序和插入排序,旨在很好地处理多种真实数据。它由Tim Peters于2002年实施使用在Python编程语言中。该算法查找已经排序的数据的子序列,并使用该知识更有效地对其余部分进行排序。这是通过将已识别的子序列(称为运行)与现有运行合并直到满足某些条件来完成的。从版本2.3开始,Timsort一直是Python的标准排序算法。如今,Timsort 已是是 Python、 JavaAndroid平台 和 GNU Octave 的默认排序算法。

思想:

针对现实中需要排序的数据分析看,大多数据通常是有部分已经排好序的数据块,Timsort 就利用了这一特点。Timsort 称这些已经排好序的数据块为 “run”,我们可以将其视为一个一个的“分区”。在排序时,Timsort迭代数据元素,将其放到不同的 run 里,同时针对这些 run ,按规则进行合并至只剩一个,则这个仅剩的 run 即为排好序的结果。

换句话说,就是分析待排序数据,根据其本身的特点,将排序好的(不管是顺序还是逆序)子序列的分为一个个run分区,当然,这个分区run也存在一定的约束,即根据序列会产生一个minrun,如果原始的run小于minrun的长度,用插入排序扩充run,直到达到条件,之后使用归并排序来合并多个run。

知乎:

首先,timsort是Python里默认的排序算法,直接就可以在cPython的源码里找到,我没记错的话好像是600多行。

timsort改进自归并排序,因为待排序数据中是一定存在一些连续递增和连续严格递减子序列的,那么timsort会找到这样的子序列,称其为run。之后便是把严格递减的run反向,整个序列就变成了好多好多个递增的run。

然后就是使用归并排序的方式merge相邻的run,等到数组中只剩下一个run的时候自然就排好序了。

实际实现时,扫描出一个run就要分析一下已有的runs要不要合并,主要是通过最后面的两到三个run的长度来进行判断。

如果初始run的数量恰好为2的整数次幂或者略小于2的整数次幂,可以进一步避免长度差距太大的两个run的合并。(如果一个run的长度大于另一个run的两倍,就可以认为差距过大了)

所以要对长度过短的run使用插入排序进行扩充,最终要保证初始run的长度在32和64之间(记不清边界条件了,没敢写成区间形式),这样可以保证长度过短时用插入排序提高效率,初始run的长度较为接近,数量也保证了后续不会存在过多的差距过大的run的合并。

在合并的时候也没有使用普通的归并排序的方式,但唯独这一小块我还不太了解。之前自己用C++语言写过一个不完整的timsort,自认为还算是比较了解的,当然合并不同的run我用的是普通的归并排序的方式。

时间有限,timesort只是了解了大概。代码参考了其他文献,用go语言改写。代码里是非原地排序。代码如下:

代码语言:txt
AI代码解释
复制
package main

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

//https://blog.csdn.net/sinat_35678407/article/details/82974174
func main() {
    rand.Seed(time.Now().Unix())
    SucCount := 0
    FaiedCount := 0
    for i := 0; i < 1000; i++ {
        arr1 := NewRandArr()
        arr2 := make([]int, len(arr1))
        copy(arr2, arr1)
        fmt.Println("原数组:", arr1)
        arr1 = timsort(arr1)
        fmt.Println("timsort排序:", arr1)
        SelectionSort(arr2)
        fmt.Println("选择排序:", arr2)

        isEqual := true
        for j := 0; j < len(arr1); j++ {
            if arr1[j] != arr2[j] {
                isEqual = false
                fmt.Println("错误")
                break
            }
        }
        if isEqual {
            SucCount++
        } else {
            FaiedCount++
        }
        fmt.Println("----")
    }
    fmt.Println("成功 = ", SucCount)
    fmt.Println("失败 = ", FaiedCount)

}
func binary_search(arr []int, left int, right int, value int) int {
    if left >= right {
        if arr[left] <= value {
            return left + 1
        } else {
            return left
        }
    } else {
        mid := left + (right-left)>>1
        if arr[mid] < value {
            return binary_search(arr, mid+1, right, value)
        } else {
            return binary_search(arr, left, mid-1, value)
        }
    }
}
func insertion_sort(arr []int) []int {
    arrLen := len(arr)
    ret := make([]int, 0)
    for i := 1; i < arrLen; i++ {
        value := arr[i]
        pos := binary_search(arr, 0, i-1, value)

        ret = append(ret, arr[:pos]...)
        ret = append(ret, value)
        ret = append(ret, arr[pos:i]...)
        ret = append(ret, arr[i+1:]...)
    }
    return ret
}
func merge(l1 []int, l2 []int) []int {
    l1Len := len(l1)
    if l1Len <= 0 {
        return l2
    }
    l2Len := len(l2)
    if l2Len <= 0 {
        return l1
    }
    ret := make([]int, 0)
    if l1[0] < l2[0] {
        ret = append(ret, l1[0])
        ret = append(ret, merge(l1[1:], l2)...)
    } else {
        ret = append(ret, l2[0])
        ret = append(ret, merge(l1, l2[1:])...)
    }
    return ret
}
func timsort(arr []int) []int {
    arrLen := len(arr)
    if arrLen <= 1 {
        return arr
    }
    runs := make([][]int, 0)
    //sorted_runs := make([][]int, 0)
    new_run := []int{arr[0]}
    for i := 1; i < arrLen; i++ {
        if arr[i] < arr[i-1] {
            runs = append(runs, new_run)
            new_run = []int{arr[i]}
        } else {
            new_run = append(new_run, arr[i])
        }
        if arrLen-1 == i {
            runs = append(runs, new_run)
            break
        }
    }
    for i := 0; i < len(runs); i++ {
        insertion_sort(runs[i])
    }
    sorted_arr := make([]int, 0)
    for i := 0; i < len(runs); i++ {
        sorted_arr = merge(sorted_arr, runs[i])
    }
    //fmt.Println(sorted_arr)
    return sorted_arr

}

//选择排序
func SelectionSort(arr []int) {
    arrlen := len(arr)
    if arrlen < 2 {
        return
    }
    // 0~n-1
    // 1~n-1
    // 2~n-1
    for i := 0; i < arrlen; i++ { // i ~ N-1
        // 最小值在哪个位置上  i~n-1
        minIndex := i
        for j := i + 1; j < arrlen; j++ { // i ~ N-1 上找最小值的下标
            if arr[j] < arr[minIndex] {
                minIndex = j
            }
        }
        arr[i], arr[minIndex] = arr[minIndex], arr[i]
    }
}

//产生一个随机数组
func NewRandArr() []int {

    Len := rand.Intn(100) + 1
    ret := make([]int, Len)
    for i := 0; i < Len; i++ {
        ret[i] = rand.Intn(1000)
    }
    return ret
}

执行结果如下:

在这里插入图片描述
在这里插入图片描述

2021-01-14:timsort是什么,如何用代码实现?

Timsort——自适应、稳定、高效排序算法

2021-01-14:timsort是什么,如何用代码实现?

评论

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2020-01-24:手写代码:快速排序。
福哥答案2020-01-24: 荷兰国旗问题三分+小于区递归+大于区递归。,相等区不用管。 代码用go语言编写。利用slice特性,可以节省两个参数。代码如下: package main import ( "fmt" "math/rand" "time" ) func main() { rand.Seed(time.Now().Unix()) sucCount := 0 failedCount := 0 for i := 0; i < 2000;
福大大架构师每日一题
2021/01/24
3740
2020-01-24:手写代码:快速排序。
十大经典排序算法最强总结(含Java、Python码实现)
所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。一个优秀的算法可以节省大量的资源。在各个领域中考虑到数据的各种限制和规范,要得到一个符合实际的优秀算法,得经过大量的推理和分析。
10JQKA
2020/12/31
9990
除了冒泡排序,你知道Python内建的排序算法吗?
Timsort 是一种对真实数据非常有效的排序算法。Tim Peters 在 2001 年为 Python 编程语言创造了 Timsort。Timsort 首先分析它要排序的列表,然后基于该分析选择合理方案。
机器之心
2018/12/17
5760
算法回顾--如何写递归?
总之递归就是”装傻”的把原始的思路表现出来,不需要关心具体过程,只需要不停的缩小问题规模,然后答案自然就会被计算出来.
屈定
2018/09/27
7900
使用ChatGPT生成了十种排序算法
当前ChatGPT非常火爆,对于程序员来说,ChatGPT可以帮助编写很多有用的代码。比如:在算法的实现上,就可以替我们省很多事。所以,小试牛刀一下,看看ChatGPT生成了排序算法怎么样?
KunkkaWu
2023/04/23
8540
使用ChatGPT生成了十种排序算法
读 Java TimSort算法 源码 笔记
本来准备看Java容器源码的。但是看到一开始发现Arrays这个类我不是很熟,就顺便把Arrays这个类给看了。Arrays类没有什么架构与难点,但Arrays涉及到的两个排序算法似乎很有意思。那顺便把TimSort算法和双指针快速排序也研究一下吧。
yuxiaofei93
2018/09/11
1.4K0
go实现归并排序
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治策略.
Johns
2022/08/12
4230
十大经典排序算法(Python代码实现)
排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。用一张图概括:
Python数据科学
2018/08/06
2.3K0
十大经典排序算法(Python代码实现)
可视化详解,一文搞懂 10 大排序算法
在本文中,我们将通过动图可视化加文字的形式,循序渐进全面介绍不同类型的算法及其用途(包括原理、优缺点及使用场景)并提供 Python 和 JavaScript 两种语言的示例代码。除此之外,每个算法都会附有一些技术说明,比如使用大 O 符号来分析不同算法的时间复杂度和空间复杂度等,也提到了一些多数人都很容易理解的一些高级概述。
unkown
2023/08/31
8010
可视化详解,一文搞懂 10 大排序算法
Tim Peters关于Timsort排序算法的说明
This describes an adaptive, stable, natural mergesort, modestly called
yuezht
2023/09/24
4271
经典排序算法和python详解(三)
经典排序算法和python详解(三):归并排序、快速排序、堆排序、计数排序、桶排序和基数排序
Minerva
2020/05/21
4850
深入了解 Python 中标准排序算法 Timsort
、稳健(即不改变等值元素间的相对顺序)的排序算法,在处理真实世界数据(经常出现部分有序情况)时表现出色,而不只是为学术研究。
叶庭云
2024/05/25
1600
2021-04-04:给定一个非负数组arr,和一个正数m的最大值。
2021-04-04:给定一个非负数组arr,和一个正数m。 返回arr的所有子序列中累加和%m之后的最大值。
福大大架构师每日一题
2021/04/04
8730
2021-04-04:给定一个非负数组arr,和一个正数m的最大值。
十大经典排序算法动图演示+Python实现
而今天这篇文章,转自 Github 上一个项目,此项目整理了 10 个常见排序算法的原理、演示和多种语言的实现。这里我们摘录其中 Python 的实现,分享给大家。
Crossin先生
2020/01/16
1.4K0
十大经典排序算法动图演示+Python实现
2021-03-08:在一个数组中,任何一个前面的数a,和任何
2021-03-08:在一个数组中,任何一个前面的数a,和任何一个后面的数b,如果(a,b)是降序的,就称为逆序对。返回逆序对个数。
福大大架构师每日一题
2021/03/08
3760
2021-03-08:在一个数组中,任何一个前面的数a,和任何
Arrays.Sort()中的那些排序算法
Arrays.Sort方法所用的排序算法主要涉及以下三种:双轴快速排序(DualPivotQuicksort)、归并排序(MergeSort)、TimSort,也同时包含了一些非基于比较的排序算法:例如计数排序。其具体最终使用哪一种排序算法通常根据类型以及输入长度来动态抉择。
Rekent
2021/03/05
8650
Arrays.Sort()中的那些排序算法
深入理解Spark 2.1 Core (十二):TimSort 的原理与源码分析
在博文《深入理解Spark 2.1 Core (十):Shuffle Map 端的原理与源码分析 》中我们提到了:
小爷毛毛_卓寿杰
2019/02/13
1.1K0
2021-07-30:两个有序数组间相加和的Topk问题。给定两个
2021-07-30:两个有序数组间相加和的Topk问题。给定两个有序数组arr1和arr2,再给定一个整数k,返回来自arr1和arr2的两个数相加和最大的前k个,两个数必须分别来自两个数组。按照降序输出。要求时间复杂度为O(klogk)。
福大大架构师每日一题
2021/07/31
3330
2021-07-30:两个有序数组间相加和的Topk问题。给定两个
从零开始学Python-day3
    列表的概念:列表可以完成大多数集合类的数据结构实现。它支持字符,数字,字符串甚至可以包含列表(所谓嵌套)。
py3study
2020/01/03
5220
从零开始学Python-day3
详解排序算法(Python实现)
与许多其他高级编程语言一样,Python语言提供了使用sorted()函数对数据进行开箱即用的功能。示例:
宇宙之一粟
2020/10/26
5200
推荐阅读
相关推荐
2020-01-24:手写代码:快速排序。
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档