Timsort:最快排序算法

Timsort(泰姆排序)是一种混合排序算法,结合了合并排序(Merge Sort)和插入排序(Insertion Sort)的特性。它由Tim Peters在2002年为Python的排序算法而设计,并在Python 2.3版本中首次实现。

Tim Sort 是Python 的sorted()和list.sort()函数使用的默认排序算法。

自从该算法被发明以来,它已被用作Python、Java、Android平台和GNU Octave中的默认排序算法。Java中使用Java的标准库(java.util.Arrays类)来使用Timsort。

import java.util.Arrays;

public class TimsortExample {

public static void main(String[] args) {

// 示例数据

int[] array = {5, 2, 9, 1, 5, 6};

// 使用Arrays.sort()方法,底层使用Timsort

Arrays.sort(array);

// 打印排序后的结果

System.out.println("Sorted Array: " + Arrays.toString(array));

}

}

这个简单的示例演示了如何使用Java的Arrays.sort()方法对一个整数数组进行排序。在实际应用中,你可以用类似的方式对其他类型的数组或对象数组进行排序。

请注意,Java的Arrays.sort()方法使用了Timsort的实现,因此你不需要自己实现Timsort算法,除非你有特殊的需求

Timsort:一种非常快速、O(n log n)、稳定的排序算法,专为现实世界构建,而不是在学术界构建。

Timsort的设计目的是克服其他排序算法在特定情况下的性能缺陷。它在实际应用中表现良好,尤其在处理有序数据或包含小规模子数组的数据时效果显著。

Timsort的主要思想是利用现实世界数据的一些特性,例如数据通常部分有序。它采用分而治之的策略,首先将数据分割成小的块,然后对这些块进行排序,最后再将这些有序块合并起来。该算法具有线性对数时间复杂度(O(n log n)),并且在最坏情况下的性能也比较好。

蒂姆排序算法

Tim Sort 背后的主要思想是利用数据中现有的顺序来最大限度地减少比较和交换的次数。它通过将数组划分为已排序的称为运行的小子数组,然后使用修改后的合并排序算法合并这些运行来实现此目的。

以下面的数组为例:arr[] = {4, 2, 8, 6, 1, 5, 9, 3, 7}。

  • 步骤 1:定义运行的大小

最小运行规模:32(由于我们的数组较小,因此忽略这一步)

  • 步骤 2:将阵列划分为运行

在这一步中,我们将使用插入排序对数组中的小子序列(运行)进行排序。

初始数组[4, 2, 8, 6, 1, 5, 9, 3, 7]

没有初始运行,因此我们将使用插入排序创建运行。

排序后的运行[2, 4], [6, 8], [1, 5, 9], [3, 7]

更新数组:[2, 4, 6, 8, 1, 5, 9, 3, 7]

  • 步骤 3:合并运行

在这一步中,我们将使用修改后的合并排序算法合并已排序的运行。

合并运行,直到整个数组排序完毕。

合并运行[2, 4, 6, 8], [1, 3, 5, 7, 9]

更新后的数组:[2, 4, 6, 8, 1, 3, 5, 7, 9]

  • 步骤 4:调整运行规模

每次合并操作后,我们都会将运行的大小加倍,直到超过数组的长度。

运行大小加倍:32、64、128(因为我们的数组很小,所以忽略这一步)

  • 第 5 步:继续合并

重复合并过程,直到整个数组排序完毕。

最终合并的运行结果[1, 2, 3, 4, 5, 6, 7, 8, 9]

最终排序后的数组为 [1,2,3,4,5,6,7,8,9]。

下面是 TimSort 的实现:

// C++ program to perform TimSort.
include <bits/stdc++.h>

using namespace std;

const int RUN = 32;

// 该函数对数组进行排序,从左索引

// 索引排序到右索引,右索引是

// 最大的 RUN

void insertionSort(int arr[], int left, int right)

{

for (int i = left + 1; i <= right; i++) {

int temp = arr[i];

int j = i - 1;

while (j >= left && arr[j] > temp) {

arr[j + 1] = arr[j];

j--;

}

arr[j + 1] = temp;

}

}

// 合并函数合并已排序的运行结果

void merge(int arr[], int l, int m, int r)

{

// 原始数组被分成两部分

// 左右两部分

int len1 = m - l + 1, len2 = r - m;

int left[len1], right[len2];

for (int i = 0; i < len1; i++)

left[i] = arr[l + i];

for (int i = 0; i < len2; i++)

right[i] = arr[m + 1 + i];

int i = 0;

int j = 0;

int k = l;

// 比较之后,我们

// 合并这两个数组

// 合并为更大的子数组

while (i < len1 && j < len2) {

if (left[i] <= right[j]) {

arr[k] = left[i];

i++;

}

else {

arr[k] = right[j];

j++;

}

k++;

}

// 复制

// 如果有的话

while (i < len1) {

arr[k] = left[i];

k++;

i++;

}

// Copy remaining element of

// right, if any

while (j < len2) {

arr[k] = right[j];

k++;

j++;

}

}

//迭代 Timsort 函数,用于对

// 数组[0...n-1]排序(类似于合并排序)

void timSort(int arr[], int n)

{

// 对大小为 RUN 的单个子数组进行排序

for (int i = 0; i < n; i += RUN)

insertionSort(arr, i, min((i + RUN - 1), (n - 1)));

// 从 RUN(或 32)开始合并。

// 它将合并

// 形成大小为 64,然后是 128、256

// 以此类推 ....

for (int size = RUN; size < n; size = 2 * size) {

// 选择

// 左侧子数组的起点。我们

// 合并

// arr[left...left+size-1] 和 arr[left+size, left+2*size-1] 合并。

// 和 arr[left+size, left+2*size-1] 进行合并。

// 每次合并后,我们

// 将 left 增加 2*size

for (int left = 0; left < n; left += 2 * size) {

//查找

// 左侧子数组

// mid+1 是右子数组的起点

//右子数组的起点

int mid = left + size - 1;

int right = min((left + 2 * size - 1), (n - 1));

//合并子数组 arr[left.....mid] &

// arr[mid+1....right]

if (mid < right)

merge(arr, left, mid, right);

}

}

}

// Utility function to print the Array

void printArray(int arr[], int n)

{

for (int i = 0; i < n; i++)

printf("%d ", arr[i]);

printf("\n");

}

// Driver program to test above function

int main()

{

int arr[] = { -2, 7, 15, -14, 0, 15, 0, 7,

-7, -4, -13, 5, 8, -14, 12 };

int n = sizeof(arr) / sizeof(arr[0]);

printf("Given Array is\n");

printArray(arr, n);

// Function Call

timSort(arr, n);

printf("After Sorting Array is\n");

printArray(arr, n);

return 0;

}

Java程序:

// Java program to perform TimSort.

class GFG {

static int MIN_MERGE = 32;

public static int minRunLength(int n)

{

assert n >= 0;

// Becomes 1 if any 1 bits are shifted off

int r = 0;

while (n >= MIN_MERGE) {

r |= (n & 1);

n >>= 1;

}

return n + r;

}

// This function sorts array from left index to

// to right index which is of size atmost RUN

public static void insertionSort(int[] arr, int left,

int right)

{

for (int i = left + 1; i <= right; i++) {

int temp = arr[i];

int j = i - 1;

while (j >= left && arr[j] > temp) {

arr[j + 1] = arr[j];

j--;

}

arr[j + 1] = temp;

}

}

// Merge function merges the sorted runs

public static void merge(int[] arr, int l, int m, int r)

{

// Original array is broken in two parts

// left and right array

int len1 = m - l + 1, len2 = r - m;

int[] left = new int[len1];

int[] right = new int[len2];

for (int x = 0; x < len1; x++) {

left[x] = arr[l + x];

}

for (int x = 0; x < len2; x++) {

right[x] = arr[m + 1 + x];

}

int i = 0;

int j = 0;

int k = l;

// After comparing, we merge those two array

// in larger sub array

while (i < len1 && j < len2) {

if (left[i] <= right[j]) {

arr[k] = left[i];

i++;

}

else {

arr[k] = right[j];

j++;

}

k++;

}

// Copy remaining elements

// of left, if any

while (i < len1) {

arr[k] = left[i];

k++;

i++;

}

// Copy remaining element

// of right, if any

while (j < len2) {

arr[k] = right[j];

k++;

j++;

}

}

// Iterative Timsort function to sort the

// array[0...n-1] (similar to merge sort)

public static void timSort(int[] arr, int n)

{

int minRun = minRunLength(MIN_MERGE);

// Sort individual subarrays of size RUN

for (int i = 0; i < n; i += minRun) {

insertionSort(

arr, i,

Math.min((i + MIN_MERGE - 1), (n - 1)));

}

// Start merging from size

// RUN (or 32). It will

// merge to form size 64,

// then 128, 256 and so on

// ....

for (int size = minRun; size < n; size = 2 * size) {

// Pick starting point

// of left sub array. We

// are going to merge

// arr[left..left+size-1]

// and arr[left+size, left+2*size-1]

// After every merge, we

// increase left by 2*size

for (int left = 0; left < n; left += 2 * size) {

// Find ending point of left sub array

// mid+1 is starting point of right sub

// array

int mid = left + size - 1;

int right = Math.min((left + 2 * size - 1),

(n - 1));

// Merge sub array arr[left.....mid] &

// arr[mid+1....right]

if (mid < right)

merge(arr, left, mid, right);

}

}

}

// Utility function to print the Array

public static void printArray(int[] arr, int n)

{

for (int i = 0; i < n; i++) {

System.out.print(arr[i] + " ");

}

System.out.print("\n");

}

// Driver code

public static void main(String[] args)

{

int[] arr = { -2, 7, 15, -14, 0, 15, 0, 7,

-7, -4, -13, 5, 8, -14, 12 };

int n = arr.length;

System.out.println("Given Array is");

printArray(arr, n);

timSort(arr, n);

System.out.println("After Sorting Array is");

printArray(arr, n);

}

}

Python3

Python3 program to perform basic timSort

MIN_MERGE = 32

def calcMinRun(n):

"""Returns the minimum length of a

run from 23 - 64 so that

the len(array)/minrun is less than or

equal to a power of 2.

e.g. 1=>1, ..., 63=>63, 64=>32, 65=>33,

..., 127=>64, 128=>32, ...

"""

r = 0

while n >= MIN_MERGE:

r |= n & 1

n >>= 1

return n + r

This function sorts array from left index to

to right index which is of size atmost RUN

def insertionSort(arr, left, right):

for i in range(left + 1, right + 1):

j = i

while j > left and arr[j] < arr[j - 1]:

arr[j], arr[j - 1] = arr[j - 1], arr[j]

j -= 1

Merge function merges the sorted runs

def merge(arr, l, m, r):

original array is broken in two parts

left and right array

len1, len2 = m - l + 1, r - m

left, right = [], []

for i in range(0, len1):

left.append(arr[l + i])

for i in range(0, len2):

right.append(arr[m + 1 + i])

i, j, k = 0, 0, l

after comparing, we merge those two array

in larger sub array

while i < len1 and j < len2:

if left[i] <= right[j]:

arr[k] = left[i]

i += 1

else:

arr[k] = right[j]

j += 1

k += 1

Copy remaining elements of left, if any

while i < len1:

arr[k] = left[i]

k += 1

i += 1

Copy remaining element of right, if any

while j < len2:

arr[k] = right[j]

k += 1

j += 1

Iterative Timsort function to sort the

array[0...n-1] (similar to merge sort)

def timSort(arr):

n = len(arr)

minRun = calcMinRun(n)

Sort individual subarrays of size RUN

for start in range(0, n, minRun):

end = min(start + minRun - 1, n - 1)

insertionSort(arr, start, end)

Start merging from size RUN (or 32). It will merge

to form size 64, then 128, 256 and so on ....

size = minRun

while size < n:

Pick starting point of left sub array. We

are going to merge arr[left..left+size-1]

and arr[left+size, left+2*size-1]

After every merge, we increase left by 2*size

for left in range(0, n, 2 * size):

Find ending point of left sub array

mid+1 is starting point of right sub array

mid = min(n - 1, left + size - 1)

right = min((left + 2 * size - 1), (n - 1))

Merge sub array arr[left.....mid] &

arr[mid+1....right]

if mid < right:

merge(arr, left, mid, right)

size = 2 * size

Driver program to test above function

if name == "main":

arr = [-2, 7, 15, -14, 0, 15, 0,

7, -7, -4, -13, 5, 8, -14, 12]

print("Given Array is")

print(arr)

Function Call

timSort(arr)

print("After Sorting Array is")

print(arr)

Cinclude

// C# program to perform TimSort.

using System;

class GFG {

public const int RUN = 32;

// This function sorts array from left index to

// to right index which is of size atmost RUN

public static void insertionSort(int[] arr, int left,

int right)

{

for (int i = left + 1; i <= right; i++) {

int temp = arr[i];

int j = i - 1;

while (j >= left && arr[j] > temp) {

arr[j + 1] = arr[j];

j--;

}

arr[j + 1] = temp;

}

}

// merge function merges the sorted runs

public static void merge(int[] arr, int l, int m, int r)

{

// original array is broken in two parts

// left and right array

int len1 = m - l + 1, len2 = r - m;

int[] left = new int[len1];

int[] right = new int[len2];

for (int x = 0; x < len1; x++)

left[x] = arr[l + x];

for (int x = 0; x < len2; x++)

right[x] = arr[m + 1 + x];

int i = 0;

int j = 0;

int k = l;

// After comparing, we merge those two array

// in larger sub array

while (i < len1 && j < len2) {

if (left[i] <= right[j]) {

arr[k] = left[i];

i++;

}

else {

arr[k] = right[j];

j++;

}

k++;

}

// Copy remaining elements

// of left, if any

while (i < len1) {

arr[k] = left[i];

k++;

i++;

}

// Copy remaining element

// of right, if any

while (j < len2) {

arr[k] = right[j];

k++;

j++;

}

}

// Iterative Timsort function to sort the

// array[0...n-1] (similar to merge sort)

public static void timSort(int[] arr, int n)

{

// Sort individual subarrays of size RUN

for (int i = 0; i < n; i += RUN)

insertionSort(arr, i,

Math.Min((i + RUN - 1), (n - 1)));

// Start merging from size RUN (or 32).

// It will merge

// to form size 64, then

// 128, 256 and so on ....

for (int size = RUN; size < n; size = 2 * size) {

// Pick starting point of

// left sub array. We

// are going to merge

// arr[left..left+size-1]

// and arr[left+size, left+2*size-1]

// After every merge, we increase

// left by 2*size

for (int left = 0; left < n; left += 2 * size) {

// Find ending point of left sub array

// mid+1 is starting point of

// right sub array

int mid = left + size - 1;

int right = Math.Min((left + 2 * size - 1),

(n - 1));

// Merge sub array arr[left.....mid] &

// arr[mid+1....right]

if (mid < right)

merge(arr, left, mid, right);

}

}

}

// Utility function to print the Array

public static void printArray(int[] arr, int n)

{

for (int i = 0; i < n; i++)

Console.Write(arr[i] + " ");

Console.Write("\n");

}

// Driver program to test above function

public static void Main()

{

int[] arr = { -2, 7, 15, -14, 0, 15, 0, 7,

-7, -4, -13, 5, 8, -14, 12 };

int n = arr.Length;

Console.Write("Given Array is\n");

printArray(arr, n);

// Function Call

timSort(arr, n);

Console.Write("After Sorting Array is\n");

printArray(arr, n);

}

}

Javascript
<script> // Javascript program to perform TimSort. let MIN\_MERGE = 32; function minRunLength(n) { // Becomes 1 if any 1 bits are shifted off let r = 0; while (n >= MIN\_MERGE) { r |= (n & 1); n >>= 1; } return n + r; } // This function sorts array from left index to // to right index which is of size atmost RUN function insertionSort(arr,left,right) { for(let i = left + 1; i <= right; i++) { let temp = arr\[i\]; let j = i - 1; while (j >= left && arr\[j\] > temp) { arr\[j + 1\] = arr\[j\]; j--; } arr\[j + 1\] = temp; } } // Merge function merges the sorted runs function merge(arr, l, m, r) { // Original array is broken in two parts // left and right array let len1 = m - l + 1, len2 = r - m; let left = new Array(len1); let right = new Array(len2); for(let x = 0; x < len1; x++) { left\[x\] = arr\[l + x\]; } for(let x = 0; x < len2; x++) { right\[x\] = arr\[m + 1 + x\]; } let i = 0; let j = 0; let k = l; // After comparing, we merge those two // array in larger sub array while (i < len1 && j < len2) { if (left\[i\] <= right\[j\]) { arr\[k\] = left\[i\]; i++; } else { arr\[k\] = right\[j\]; j++; } k++; } // Copy remaining elements // of left, if any while (i < len1) { arr\[k\] = left\[i\]; k++; i++; } // Copy remaining element // of right, if any while (j < len2) { arr\[k\] = right\[j\]; k++; j++; } } // Iterative Timsort function to sort the // array\[0...n-1\] (similar to merge sort) function timSort(arr, n) { let minRun = minRunLength(MIN\_MERGE); // Sort individual subarrays of size RUN for(let i = 0; i < n; i += minRun) { insertionSort(arr, i, Math.min( (i + MIN\_MERGE - 1), (n - 1))); } // Start merging from size // RUN (or 32). It will // merge to form size 64, // then 128, 256 and so on // .... for(let size = minRun; size < n; size = 2 \* size) { // Pick starting point // of left sub array. We // are going to merge // arr\[left..left+size-1\] // and arr\[left+size, left+2\*size-1\] // After every merge, we // increase left by 2\*size for(let left = 0; left < n; left += 2 \* size) { // Find ending point of left sub array // mid+1 is starting point of right sub // array let mid = left + size - 1; let right = Math.min((left + 2 \* size - 1), (n - 1)); // Merge sub array arr\[left.....mid\] & // arr\[mid+1....right\] if(mid < right) merge(arr, left, mid, right); } } } // Utility function to print the Array function printArray(arr,n) { for(let i = 0; i < n; i++) { document.write(arr\[i\] + " "); } document.write("
"); } // Driver code let arr = \[ -2, 7, 15, -14, 0, 15, 0, 7, -7, -4, -13, 5, 8, -14, 12 \]; let n = arr.length; document.write("Given Array is
"); printArray(arr, n); timSort(arr, n); document.write("After Sorting Array is
"); printArray(arr, n); </script>

Output

Given Array is

-2 7 15 -14 0 15 0 7 -7 -4 -13 5 8 -14 12

After Sorting Array is

-14 -14 -13 -7 -4 -2 0 0 5 7 7 8 12 15 15

https://www.jdon.com/71611.html

相关推荐
你也向往长安城吗6 分钟前
推荐一个三维导航库:three-pathfinding-3d
javascript·算法
karrigan16 分钟前
async/await 的优雅外衣下:Generator 的核心原理与 JavaScript 执行引擎的精细管理
javascript
wycode24 分钟前
Vue2实践(3)之用component做一个动态表单(二)
前端·javascript·vue.js
wycode1 小时前
Vue2实践(2)之用component做一个动态表单(一)
前端·javascript·vue.js
第七种黄昏1 小时前
Vue3 中的 ref、模板引用和 defineExpose 详解
前端·javascript·vue.js
我是哈哈hh2 小时前
【Node.js】ECMAScript标准 以及 npm安装
开发语言·前端·javascript·node.js
张元清2 小时前
电商 Feeds 流缓存策略:Temu vs 拼多多的技术选择
前端·javascript·面试
pepedd8643 小时前
浅谈js拷贝问题-解决拷贝数据难题
前端·javascript·trae
@大迁世界3 小时前
useCallback 的陷阱:当 React Hooks 反而拖了后腿
前端·javascript·react.js·前端框架·ecmascript
小高0073 小时前
📌React 路由超详解(2025 版):从 0 到 1 再到 100,一篇彻底吃透
前端·javascript·react.js