排序的稳定性
稳定性: 两记录排序码相等,稳定的排序算法可以保证即使值相等,排序后顺序仍然不变。
因为原序列的顺序可能隐含一些信息,稳定排序算法维持这些信息。
冒泡排序(相邻元素排序调):如若两个数值相等,则不会发生交换,故该排序是稳定的。
选择排序(每次选最小的排序):如果较小的元素出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了,故该排序是稳定的。
插入排序(在已经有序的队列里插值):比较是从有序序列的末尾开始,
如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。插入排序是稳定的。
快速排序(从左往右,基数右移,小于基数前调):快速排序是一个不稳定的排序算法,不稳定发生在基数元素和a[j] 交换的时刻。详见下文快速排序的介绍
归并排序(将序列递归地分成短序列):稳定的排序算法。
希尔排序(shell)(按照不同步长对元素进行插入排序):不稳定的排序算法
堆排序(节点排序):当为n /2-1, n/2-2, …1这些个父节点选择元素时,就会破坏稳定性。有可能第n/2个父节点交换把后面一个元素交换过去了,而第n/2-1个父节点把后面一个相同的元素没有交换,这2个相同的元素之间的稳定性就被破坏了 。
综上,选择排序、快速排序、希尔排序、堆排序等不是稳定的排序算法,而 冒泡排序、插入排序、归并排序和基数排序等是稳定的排序算法。
这部分详细见百度百科
几种排序算法总结
- BUBBLE 冒泡排序
从左往右,找到最大的移至最后
示例代码:
int i,j,k;
for(i=0;i<n-1;i++) //找出n-1个最大的放在右边
{
for(j=0;j<n-1-i;j++) //排好的序列逐步从右向左推进
{
if(ap[j]>ap[j+1])
{
swap(ap[j],ap[j+1]); //交换
}
}}
- SELECT 选择排序
从左往右,找到最小的移至前面,排好的序列由左向右推进。
示例代码:
void sort (int array[],int n)
{
int i,j,k,t;
for (i=0;i<n-1;i++) //需要n-1次
{
k=i; //k保存最小的值
for(j=i+1;j<n;j++) //从左向右推进
if(array[k]>array[j])
k=j; //k保存最小的值
swap(array[k],array[i]);//交换
}
}
- INSERT 插入排序
从左往右,依次为该数找到相应的位置插入前面序列
- MERGE 归并排序
将数列多次分半,直到每组有两个数,对每小组进行排序,成为有序数列,再往前合并其他小组
- QUICK 快速排序 O(N*logN)
visualgo里的排序流程
for each (unsorted) partition set first element as pivot
for i = pivotIndex + 1 to rightmostIndex
if element[i] < element[pivot]
swap(i, storeIndex);
storeIndex++ swap(pivot, storeIndex - 1)
先从数列中取出一个数作为基准数。一般为第一个数。
分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
再对左右区间重复第二步,直到各区间只有一个数。
总结:用i,j两个数左右搜索,将第一个值存入X,右往左找比X小的数,左往右找X大的数,填坑,i,j逼进,直到ij相等。此时,左边是比X小的数,右边是比X大的数
示例
主函数
int main()
{
int array[10],k;
int len;//要排列的数的长度,不能超过10个
cout<<"the len";
cout<<endl;
cin>>len;
cout<<"The orginal array are:"<<endl;
for(int k=0; k<len; k++)
cin>>array[k];
quickSort(array,0,len-1);
cout<<"The sorted array are:"<<endl;
for(int k=0; k<len; k++)
cout<<array[k]<<" ";
cout<<endl;
system("pause");
return 0;
}
版本一
void quickSort(int s[], int l, int r) //主函数
{
if (l< r)
{
int i = l, j = r, x = s[l];
while (i < j) //直到i==j
{
while(i < j && s[j]>= x) // 从右向左找第一个小于x的数
j–;
if(i < j)
s[i++] = s[j];//s[i] = s[j],++i;
while(i < j && s[i]< x) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
s[j–] = s[i];//s[j] = s[i],–j;
}
s[i] = x;
quickSort(s, l, i – 1); // 递归调用
quickSort(s, i + 1, r);
}
}
版本二:
//一次划分
int Partition(int r[], int start, int end)
{
if(r==NULL ||start <0||end < start)
throw new std::exception("Invailid Paramater");
//初始化
int i=start;
int j=end;
int temp;
while (i<j)
{
while (i<j && r[i]<= r[j])
j--;
if (i<j) //右往左找到大值,交换值且i右移
{
//将较小记录交换到前面
swap(r[i],r[j]);
i++;
}
while (i<j && r[i]<=r[j])
i++; //左侧扫描
if (i<j)
{
swap(r[i],r[j]); //将较大记录交换到后面
j--;
}
}
return i; //i为轴值记录的最终位置
}
//快速排序
void quickSort(int r[], int start, int end)
{
if (start<end)
{
//递归结束
int pivot=Partition(r, start, end); //一次划分
quickSort(r, start, pivot-1);//递归地对左侧子序列进行快速排序
quickSort(r, pivot+1, end); //递归地对右侧子序列进行快速排序
}
}