总结部分排序

排序

1.插入排序

直接将值一个一个插入,然后往后调整。

2.希尔排序

1.进行预排序(使整个数组的顺序变得比较有序,大的在后面,小的在前面)

2.再进行插入排序

快排:

1. hoare版本

最快情况下时间复杂度是n * log n

最坏情况下时间复杂度是n ^ 2

如果接近有序或者是有序的情况下,可以加上三数取中的方法:

三数取中(即:找到比最大值小的,比最小值大的值)

begin mid end

加入三数取中后,快排瞬间从最坏的情况跳到最好的情况,这样下的快排几乎不会出现最坏情况,这样的情况下,快排的时间复杂度可以看做是O(N*logN)

或者可以使用随机key的方法,这里不加以演示,因为VS中自带的rand并不是真正的随机数

小区间优化,快排分割的小区间时,直接用插入排序即可。

2. 挖坑法

  1. 将第一坑位置的值先交给key,右边找小于key的值并将小于key的值交给坑位置,然后该位置形成一个新的坑。

  1. .然后左边走,找到大于key的值并将左边的值交给坑,然后该位置形成一个新的坑。

  1. 然后重复上序操作。

3. 前后指针版本

  1. 先将第一个位置标记为key,并用prev指针指向该位置,cur指针指向该位置的后一个位置

  1. 用cur找小于key的值,找到了之后将prev的值与cur指向的指针进行交换,prev++

  1. 重复上序操作,如果cur出现越界,将key的值指向目前prev的位置,并继续进行上序操作,直至prev指针访问的最后一个值

4.非递归下的快排

需要用到栈 ,如果要先处理左,就将右先入栈(因为栈是先入后出)。

用队列也可以,就类似于层序遍历。

1.归并排序

(2)非递归

  1. 用rangeN标记每次归并的数据个数,从一开始,因为一个数据可以认为是有序的,可以直接归并,并不需要多加判断

  1. 当进行完第一次归并后,将rangeN * 2,在进行下一次归并排序,直到这组数据完全有序

  1. 可以归并一部分拷贝一部分,也可以归并完之后再进行拷贝

for(int i = 0; i <n -1; i += 2 * rangeN)
{
    int begin1 = i,  end1 = i + rangeN-1; 
    int begin2 = i + rangeN, end2 =i + rangeN * 2 - 1;
    memcpy(a + i, tmp + i, sizeof(end2+i-1));
}

注意:创建的begin1不可能越界,但end1,begin2,end2都可能越界,因为这里创建的空间只有n的大小

可以向下面这样修正,添加到for循环中去

修正路线

if(end1 >= n)
{
    end1 = n - 1;
    //不存在区间
    begin2 = n;
    end2 = n + 1;
}
else if(begin2 >= n)
{
    
}

直接跳过路线:

if(end1 >= n){    //修正区间 -> 归并完之后拷贝数据 或者  归并每组先拷贝再继续         
     break;
}
if(begin2 >= n){    
     break;
}
if(end2 >= n)
{    
     end2 = n - 1;
}

快速排序的小问题

对于快排来说,如果有大量重复的数据,就会出现性能下降的问题。

可以采用三路划分来进行操作,就可以不出现这种问题。

画图

cur -- c

left -- l

right -- r

  1. a[c] < key, 交换l和c的位置,l++,c++

  1. a{c] == key ,c++

  1. a[c] > key, 交换c和r的位置,r++

  1. c > r 就结束了

int key = begin + rand % (end-begin)

怎么判断稳定性:

相同的数,需要保证他们的相对顺序不变,那么就是稳定的。

下面是排序的稳定性的表格:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值