如果排序算法在键相等的情况下保持记录的相对顺序,则称其为稳定算法。
Input : (1, 5), (3, 2) (1, 2) (5, 4) (6, 4)
We need to sort key-value pairs in the increasing order of keys of first digit
There are two possible solution for the two pairs where the key is same i.e. (1, 5) and (1, 2) as shown below:
OUTPUT1: (1, 5), (1, 2), (3, 2), (5, 4), (6, 4)
OUTPUT2: (1, 2), (1, 5), (3, 2), (5, 4), (6, 4)
A stable algorithm produces first output. You can see that (1, 5) comes before (1, 2) in the sorted order, which was the original order i.e. in the given input, (1, 5) comes before (1, 2).
Second output can only be produced by an unstable algorithm. You can see that in the second output, the (1, 2) comes before (1, 5) which was not the case in the original input.
有些排序算法本质上是稳定的,例如插入排序,合并排序,冒泡排序等。而有些排序算法则不是稳定的,例如堆排序,快速排序等。
QuickSort是一种不稳定的算法,因为我们根据枢轴的位置(不考虑其原始位置)进行元素交换。
如何使QuickSort稳定?
Quicksort可能很稳定,但通常不是那样实现的。要使其稳定,要么需要N阶存储(如在朴素的实现中那样),要么就地版本需要一些额外的逻辑。
在下面的实现中,我们使用额外的空间。这个想法是制作两个单独的列表:
1)第一个列表包含小于数据透视表的项目。
2)第二个列表包含大于枢轴的项目。
Java
// Java code to implement Stable QuickSort.
// The code uses middle element as pivot.
import java.util.*;
class GFG
{
public static ArrayList quickSort(ArrayList ar)
{
// Base case
if(ar.size() <= 1)
{
return ar;
}
else
{
// Let us choose middle element a pivot
int mid = ar.size() / 2;
int pivat = ar.get(mid);
// key element is used to break the array
// into 2 halves according to their values
ArrayList smaller = new ArrayList<>();
ArrayList greater = new ArrayList<>();
// Put greater elements in greater list,
// smaller elements in smaller list. Also,
// compare positions to decide where to put.
for(int ind = 0; ind < ar.size(); ind++)
{
int val = ar.get(ind);
if( ind != mid )
{
if( val < pivat )
{
smaller.add(val);
}
else if(val > pivat)
{
greater.add(val);
}
else
{
// If value is same, then considering
// position to decide the list.
if(ind < mid)
{
smaller.add(val);
}
else
{
greater.add(val);
}
}
}
}
ArrayList ans = new ArrayList();
ArrayList sa1 = quickSort(smaller);
ArrayList sa2 = quickSort(greater);
// add all elements of smaller list into ans list
for(Integer val1 : sa1)
ans.add(val1);
// add pivat element into ans list
ans.add(pivat);
// add all elements of greater list into ans list
for(Integer val2 : sa2)
ans.add(val2);
// return ans list
return ans;
}
}
// Driver code
public static void main(String args[])
{
int ar[] = {10, 7, 8, 9, 1, 5};
ArrayList al = new ArrayList<>();
al.add(10);
al.add(7);
al.add(8);
al.add(9);
al.add(1);
al.add(5);
ArrayList sortedAr = quickSort(al);
System.out.println(sortedAr);
}
}
// This code is contributed by Naresh Saharan
Python3
# Python code to implement Stable QuickSort.
# The code uses middle element as pivot.
def quickSort(ar):
# Base case
if len(ar) <= 1:
return ar
# Let us choose middle element a pivot
else:
mid = len(ar)//2
pivot = ar[mid]
# key element is used to break the array
# into 2 halves according to their values
smaller,greater = [],[]
# Put greater elements in greater list,
# smaller elements in smaller list. Also,
# compare positions to decide where to put.
for indx, val in enumerate(ar):
if indx != mid:
if val < pivot:
smaller.append(val)
elif val > pivot:
greater.append(val)
# If value is same, then considering
# position to decide the list.
else:
if indx < mid:
smaller.append(val)
else:
greater.append(val)
return quickSort(smaller)+[pivot]+quickSort(greater)
# Driver code to test above
ar = [10, 7, 8, 9, 1, 5]
sortedAr = quickSort(ar)
print(sortedAr)
[1, 5, 7, 8, 9, 10]
在上面的代码中,我们有意使用中间元素作为枢轴,以演示如何考虑位置作为比较的一部分。如果我们将last元素用作数据透视表,则代码将大大简化。对于最后一个元素,我们总是可以在较小的列表中放入相等的元素。