排序: 快排 歸併排序
二分: 整數 浮點數
快速排序
1.主要思想---->代碼
2.每個題的模板寫出來—> 默寫
3.題目------> 有對應解決方案
以上3個步驟反覆進行
快速排序----->分治
1.確定分界點q[l],q[(l+r)/2],q[r] 隨機
***2.劃分區間(調整區間) 兩部分
|---------------------------|--------------------------|
<=x >=x
3.遞歸處理左右兩段
劃分區間解法1
1.開兩個數組: a[], b[]
2.q[l~~r]:
q[i]<=x; x–>a[]
q[i]>=x; x–>b[]
3.a[]–>q[], b[]—>q[];
劃分區間解法2
3 1 2 3 5 x = 3
選定一個哨兵值,哨兵值兩邊所有元素與哨兵值比較,左邊的進行比較如果大於則交換,右邊的進行比較,若小於則交換。
快速排序模板:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e6+10;
int n;
int a[N];
void quick_sort(int a[],int l,int r){
if(l>=r) return;
int i=l-1,j=r+1;
int x=a[l];
while(i<j){
do i++;while(a[i]<x); //指針1
do j--;while(a[j]>x);//指針2
if(i<j) swap(a[i],a[j]);
}
quick_sort(a,l,j);
quick_sort(a,j+1,r);
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
quick_sort(a,0,n-1);
for(int i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
歸併排序
1.主要思想---->代碼
2.每個題的模板寫出來—> 默寫
3.題目------> 有對應解決方案
以上3個步驟反覆進行
歸併排序----->分治
1.找分界點---->確定分界點mid==(l+r)/2
2.遞歸排序左邊和右邊
***3.歸併(合二爲一)
雙指針算法:
1 3 5 7 9 指針1
2 4 5 8 10 指針2
^
雙路歸併,合二爲一(1and2 =1,指針1++,…)
res: 1 2 3 4 5 5 7 8 9 10
穩定不穩定沒什麼nuan 用。。。!
n
n/2 n/2
n/4 n/4 n/4 n/4
.
.
.
.
最後是排好序的1/n份數值。
歸併排序模版:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e6+10;
int n;
int a[N],tmp[N];
void merge_sort(int a[],int l,int r){
if(l>=r) return;
int mid=(l+r)>>1;
merge_sort(a,l,mid),merge_sort(a,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<mid&&j<=r)
if(a[i]<=a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(i=l,j=0;i<=r;i++,j++) a[i]=tmp[j];
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
merge_sort(a,0,n-1);
for(int i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
這3種排序最快胡是歸併,然後是快排,最後是sort。
二分(整數和實數)
整數二分1;
前部分 後部分
|-----------mid---------------|------------------------------|
l mid r
1.找中間值 mid=(l+r)/2;
if(check(mdi)) true 時,mid在前部分(進行邊界分界),false時在後部分(進行邊界分界)。
二分的本質: 只要擁有單調性,一定可以二分,可以二分的但不一定單調。所以整數二分的本質是 :邊界。
整數二分算法1(mid在左部分):
區間[l,r]被劃分爲[l,mid]和[mid+1,r]時使用。
int besearch_1(int l,int r){
while(l<r){
int mid=l+r>>1;
if(check((mid)) r=mid;//check判斷mid是否滿足性質
else l=mid+1;
整數二分算法1(mid在右部分):
整數二分2;
前部分 後部分
|--------------------------|---------------mid---------------|
l mid r
1.找中間值 mid=(l+r)/2;
if(check(mdi)) true 時,mid在後部分(進行邊界分界),false時在前部分(進行邊界分界)。
區間[l,r]被劃分爲[l,mid]和[mid+1,r]時使用。
int besearch_1(int l,int r){
while(l<r){
int mid=(l+r+1)>>1;//+1可以防止死循環 下一語句判斷爲true時不會出錯。
if(check((mid)) l=mid;//check判斷mid是否滿足性質
else r=mid-1;
針對二分問題: 邊界寫好–>寫二分–>判斷(答案在左右的哪部分)是哪一種,前部分l+r,後部分l+r+1的問題,而扽不需要考慮是否無解,但是可以得出來元問題是否無解。
浮點數二分:
不需要處理邊界問題,所以比較容易。
舉例子:
#include<iostream>
using namespace std;
int main(){
double x;
cin>>x;
double l=0,r=x;
while(r-l>1e-8) {//區間大於10的-8次方,題目讓保留5位小數,就多2,就不會有誤差問題,這是經驗問題
double mid=(l+r)/2;
if(mid*mid>=x) r=mid;//不需要處理邊界,沒+1和-1
else l=mid;
}
printf("%lf\n",l);
return 0;
}
question:785,786,787,788,789,790