数据结构与算法之美(排序优化)

一、如何选择合适的排序算法?

1.排序算法一览表

在这里插入图片描述

2.为什选择快速排序?

1)线性排序时间复杂度很低但使用场景特殊,如果要写一个通用排序函数,不能选择线性排序。
2)为了兼顾任意规模数据的排序,一般会首选时间复杂度为O(nlogn)的排序算法来实现排序函数。
3)同为O(nlogn)的快排和归并排序相比,归并排序不是原地排序算法,所以最优的选择是快排。

二、如何优化快速排序?

导致快排时间复杂度降为O(n)的原因是分区点选择不合理,

最理想的分区点是:被分区点分开的两个分区中,数据的数量差不多。

如何优化分区点的选择?

1.三数取中法

①从区间的首、中、尾分别取一个数,然后比较大小,取中间值作为分区点。
②如果要排序的数组比较大,那“三数取中”可能就不够用了,可能要“5数取中”或者“10数取中”。

int NumberOfThree(int arr[],int low,int high)
{
    
    
	int mid = low + ((high - low) >> 1);//右移相当于除以2
 
	if (arr[mid] > arr[high])
	{
    
    
		Swap(arr[mid],arr[high]);
	}
	if (arr[low] > arr[high])
	{
    
    
		Swap(arr[low],arr[high]);
	}
	if (arr[mid] > arr[low]) 
	{
    
    
		Swap(arr[mid],arr[low]);
	}
	//此时,arr[mid] <= arr[low] <= arr[high]
	return arr[low];
}

2.随机法

每次从要排序的区间中,随机选择一个元素作为分区点。

int Random(int a[], int low, int high)//在low和high间随机选择一元素作为划分的基准
{
    
       
    srand(time(0));
    int pivot = rand()%(high - low) + low;
    Swap(a[pivot],a[low]); //把随机基准位置的元素和low位置元素互换
    return a[low];
}

3.警惕快排的递归发生堆栈溢出

①限制递归深度,一旦递归超过了设置的阈值就停止递归。

②在堆上模拟实现一个函数调用栈,手动模拟递归压栈、出栈过程,这样就没有系统栈大小的限制。

三、通用排序函数实现技巧

1.数据量不大时,可以采取用时间换空间的思路
2.数据量大时,优化快排分区点的选择
3.防止堆栈溢出,可以选择在堆上手动模拟调用栈解决
4.在排序区间中,当元素个数小于某个常数是,可以考虑使用O(n^2)级别的插入排序
5.用哨兵简化代码,每次排序都减少一次判断,尽可能把性能优化到极致

猜你喜欢

转载自blog.csdn.net/qq_54729417/article/details/123449800
今日推荐