1.快速排序介绍
快速排序算法是在冒泡排序的基础上进行改进的一种算法,
其实现的基本思想是:通过一次排序将整个无序表分成相互独立的两部分,
其中一部分中的数据都比另一部分中包含的数据的值小,
然后继续沿用此方法分别对两部分进行同样的操作,直到每一个小部分不可再分,所得到的整个序列就成为了有序序列。
2.快速排序相比其他排序算法的优点
快速排序相比其他排序算法有以下优点:
高效性:快速排序是一种高效的排序算法,平均时间复杂度为O(nlogn)。在大多数情况下,快速排序的性能优于其他常见的排序算法,如冒泡排序、插入排序和选择排序。
原地排序:快速排序是一种原地排序算法,它不需要额外的辅助空间来存储临时数据。它通过交换数组中的元素来进行排序,节省了额外的内存空间。
分治思想:快速排序使用分治法的思想,将待排序的数组分割成较小的子数组,然后分别对子数组进行排序。这种分而治之的策略可以提高排序的效率,并且可以通过递归的方式实现。
适应性强:快速排序适用于各种不同类型的数据,包括整数、浮点数和字符串等。它可以根据具体的应用场景进行优化,例如选择合适的基准元素、使用随机化的方法来打破输入数据的有序性等
3.快速排序思路
从数列中挑出一个元素,称为 “基准”。
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区操作。
递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
注意:基准元素可以是任何一个数组内的元素;一般选择首末元素或随机元素;
此处为动图演示:
4. 复杂度
平均时间复杂度:O(NlogN)
最佳时间复杂度:O(NlogN)
最差时间复杂度:O(N^2)
空间复杂度:根据实现方式的不同而不同
5.递归法代码实现
void kuaipai(int arr[], int left, int right)//快排函数,传入待排序数组,首末两数组下标
{
int i, j, t, temp;
if (left > right)//left>right时,说明已经排序完成
return;
temp = arr[left]; //temp中存的就是基准数(此处选择用首元素为基准)
i = left;
j = right;//遍历需要,不改变传入的数字,i为左指向,j为右指向
while (i != j)
{
while (arr[j] >= temp && i < j)//先从右往左找 ,当目前指向元素的值大于基准时(说明符合在基准右边),使指向左移
j--;
while (arr[i] <= temp && i < j) //再从左往右找 ,当目前指向元素的值小于基准时(说明符合在基准右边),使指向右移
i++;
if (i < j)//当左指向与右指向没有相遇时
swap(&arr[i],&arr[j]); //交换两个数在数组中的位置
}//每进行一轮都会找出一个位置不正确的元素交换至正确位置
arr[left] = arr[i]; //将基准排到正确位置
arr[i] = temp;
kuaipai(arr,left, i - 1);//继续处理左边的,这里是一个递归的过程
kuaipai(arr, i + 1, right);//继续处理右边的,这里是一个递归的过程
}
注意:
1.选取元素与循环内代码关系
选取最左元素(最右)时,则应该从最右(最左)开始移动指向。
原因:避免在代码倒数3,4行时,将大于基准元素的元素移动到比基准小的区域,造成永远无法排序正确。
先移动相反方向元素,可以使得最后一次循环时,两个指向,同时指向正确的元素。
2.快排适用数组的类型
快排比较适用于顺序比较乱的数组(从复杂度角度出发)
可以使得选取的基准元素是排序区间中最大或最小的元素的概率减少,使得分割之后枢纽左右两边元素数量分布地比较均匀,倾向于最好情况。
补充:优化改进
在上述代码中使用的递归方法,是一种使用相同的方法,通过解决问题的子集以达到解决整个问题的方法,是一种使用有限代码解决“无限”计算的方法。
改进原因:递归使用时调用堆栈,使用堆栈来保存每一次递归调用返回时所需要的条件,堆栈的大小是有限的。
改进思路:递归转化为迭代。迭代的思想主要在于,在同一栈帧中不断使用现有数据计算出新的数据,然后使用新的数据来替换原有数据。