目录
归并排序:
完整代码:
快速排序:
思路:进行二分,然后合并。对于合并的两个模块,每一个模块必定已排好,因为是排完才合并。
例如2 4 6 | 1 3 7;双“指针”,一个指向左边、一个指向右边。
右边1<左边2 1进入b数组 此时2 4 6|3 7 b={1};右边3>左边2 2进入b数组 此时4 6|3 7 b={1,2}……
以此类推。
由此发现,右边的进入时,左边剩下了多少就有多少逆序对,并且合并回溯过程中,每一个数都会和它前面的数进行分组(就是这里的左右)。
所以,只需在需要将右边数加入时加上这条语句即可ans += (ll)(mid-p1+1);mid时最后一个左组元素的下标。
注意:等号的时候让左组进入,因为相等这不是逆序对。
void _merge(int l,int mid,int r){ int p1 = l,p2 = mid+1; for(int i = l;i <= r;i++){ if(((a[p1] <= a[p2])||(p2 > r))&&p1<=mid){ b[i] = a[p1++]; }//等号无所谓,这里为了求逆对数,相等的情况让前面的先进去,主要靠后面进行求逆对数 else { b[i] = a[p2++]; } } for(int i = l;i <= r;i++) a[i] = b[i]; return ; } void erfen(int l,int r){ int mid = (l+r)>>1; if(l < r){ erfen(l,mid); erfen(mid+1,r); } _merge(l,mid,r); return ; }找到一个基准点,小于它的在左侧,大于它的在右侧,然后递归对两侧同样执行。
void q_sort(int l,int r){ int i = l,j = r; int mid = (l+r)>>1; int x = a[mid]; while(i <= j){ while(a[i] < x) i++; while(a[j] > x) j--; if(i <= j){ swap(a[i],a[j]); i++;j--; } } if(l < j) q_sort(l,j); if(i < r) q_sort(i,r); }寻找第k小数,那么就进行改进。
如果找到了一个数,基准点位置最后在….x…..,如果x<k的话,左侧肯定不会是第k小数,都没有k个数,左侧不必再排序,砍掉一半。如果x>k的话,右侧肯定不会是第k小数,因为左侧多余k个数,右侧都大于左侧,所以肯定在左侧。
void q_sort(int l,int r){ int i = l,j = r; int mid = (l+r)>>1; int x = a[mid]; while(i <= j){ while(a[i] < x) i++; while(a[j] > x) j--; if(i <= j){ swap(a[i],a[j]); i++;j--; } } if(k == i-1){ printf("%d\n",a[k]); return ; } else if(k < i-1){ q_sort(l,i-1); } else q_sort(i,r); }