《趣學演算法》第三章 分治法原始碼
阿新 • • 發佈:2020-09-02
分治法程式碼實現
目錄
1、猜數遊戲——二分搜尋技術
//program 3-1 #include<iostream> #include<cstdlib> #include<algorithm> using namespace std; const int M=10000; int x,n,i; int s[M]; int BinarySearch(int n,int s[],int x) { int low=0,high=n-1; //low指向有序陣列的第一個元素,high指向有序陣列的最後一個元素 while(low<=high) { int middle=(low+high)/2; //middle為查詢範圍的中間值 if(x==s[middle]) //x等於查詢範圍的中間值,演算法結束 return middle; else if(x>s[middle]) //x大於查詢範圍的中間元素,則從左半部分查詢 low=middle+1; else //x小於查詢範圍的中間元素,則從右半部分查詢 high=middle-1; } return -1; } int main() { cout<<"該數列中的元素個數n為:"; while(cin>>n) { cout<<"請依次輸入數列中的元素:"; for(i=0;i<n;i++) cin>>s[i]; sort(s,s+n); cout<<"排序後的陣列為:"; for(i=0;i<n;i++) { cout<<s[i]<<" "; } cout<<endl; cout<<"請輸入要查詢的元素:"; cin>>x; i=BinarySearch(n,s,x); if(i==-1) cout<<"該數列中沒有要查詢的元素"<<endl; else cout<<"要查詢的元素在第"<<i+1<<"位"<<endl; } return 0; }
2、合久必分,分久必合——合併排序
//program 3-2 #include <iostream> #include <cstdlib> using namespace std; void Merge(int A[], int low, int mid, int high) { int *B=new int[high-low+1];//申請一個輔助陣列 int i=low, j=mid+1, k=0; while(i<=mid && j<=high) {//按從小到大存放到輔助陣列B[]中 if(A[i]<=A[j]) B[k++]=A[i++]; else B[k++]=A[j++]; } while(i<=mid) B[k++]=A[i++];//將陣列中剩下的元素放置B中 while(j<=high) B[k++]=A[j++]; for(i=low, k=0; i<=high; i++) A[i]=B[k++]; } void MergeSort(int A[], int low, int high) { if(low<high) { int mid=(low+high)/2;//取中點 MergeSort(A, low, mid);//對A[low:mid]中的元素合併排序 MergeSort(A, mid+1, high);//對A[mid+1:high]中的元素合併排序 Merge(A, low, mid, high);//合併 } } int main() { int n, A[100]; cout<<"請輸入數列中的元素個數n為:"<<endl; cin>>n; cout<<"請依次輸入數列中的元素:"<<endl; for(int i=0; i<n; i++) cin>>A[i]; MergeSort(A,0,n-1); cout<<"合併排序結果:"<<endl; for(int i=0;i<n;i++) cout<<A[i]<<" "; cout<<endl; return 0; }
3、兵貴神速——快速排序
//program 3-3 #include <iostream> using namespace std; int Partition(int r[],int low,int high)//劃分函式 { int i=low,j=high,pivot=r[low];//基準元素 while(i<j) { while(i<j&&r[j]>pivot) j--;//向左掃描 if(i<j) { swap(r[i++],r[j]);//r[i]和r[j]交換後i+1右移一位 } while(i<j&&r[i]<=pivot) i++;//向右掃描 if(i<j) { swap(r[i],r[j--]);//r[i]和r[j]交換 後j-1左移一位 } } return i;//返回最終劃分完成後基準元素所在的位置 } int Partition2(int r[],int low,int high)//劃分函式 { int i=low,j=high,pivot=r[low];//基準元素 while(i<j) { while(i<j&&r[j]>pivot) j--;//向左掃描 while(i<j&&r[i]<=pivot) i++;//向右掃描 if(i<j) { swap(r[i++],r[j--]);//r[i]和r[j]交換 } } if(r[i]>pivot) { swap(r[i-1],r[low]);//r[i-1]和r[low]交換 return i-1;//返回最終劃分完成後基準元素所在的位置 } swap(r[i],r[low]);//r[i]和r[low]交換 return i;//返回最終劃分完成後基準元素所在的位置 } void QuickSort(int R[],int low,int high)//實現快排演算法 { int mid; if(low<high) { mid=Partition2(R,low,high); //基準位置 QuickSort(R,low,mid-1);//左區間遞迴快排 QuickSort(R,mid+1,high);//右區間遞迴快排 } } int main() { int a[100]; int i,N; cout<<"請先輸入要排序的資料的個數:"; cin>>N; cout<<"請輸入要排序的資料:"; for(i=0;i<N;i++) cin>>a[i]; cout<<endl; QuickSort(a,0,N-1); cout<<"排序後的序列為:"<<endl; for(i=0;i<N;i++) cout<<a[i]<<" " ; cout<<endl; return 0; }
4、效率至上——大整數乘法
//program 3-4
#include <stdlib.h>
#include <cstring>
#include <iostream>
using namespace std;
#define M 100
char sa[1000];
char sb[1000];
typedef struct _Node
{
int s[M];
int l; //代表字串的長度
int c;
} Node,*pNode;
void cp(pNode src, pNode des, int st, int l)
{
int i, j;
for(i=st, j=0; i<st+l; i++, j++)
{
des->s[j] = src->s[i];
}
des->l = l;
des->c = st + src->c; //次冪
}
/*
分治法 大數乘法
X = A*10^n + B
Y = C*10^m + D
X*Y = A*C*10^(n+m) + A*D*10^n + B*C*10^m + B*D
*/
void add(pNode pa, pNode pb, pNode ans)
{
int i,cc,k,palen,pblen,len;
int ta, tb;
pNode temp;
if((pa->c<pb->c)) //保證Pa的次冪大
{
temp = pa;
pa = pb;
pb = temp;
}
ans->c = pb->c;
cc = 0;
palen=pa->l + pa->c;
pblen=pb->l + pb->c;
if(palen>pblen)
len=palen;
else
len=pblen;
k=pa->c - pb->c;
for(i=0; i<len-ans->c; i++) //結果的長度最長為pa,pb之中的最大長度減去最低次冪
{
if(i<k)
ta = 0;
else
ta = pa->s[i-k];//次冪高的補0,大於低的長度後與0進行計算
if(i<pb->l)
tb = pb->s[i];
else
tb = 0;
if(i>=pa->l+k)
ta = 0;
ans->s[i] = (ta + tb + cc)%10;
cc = (ta + tb + cc)/10;
}
if(cc)
ans->s[i++] = cc;
ans->l = i;
}
void mul(pNode pa, pNode pb, pNode ans)
{
int i, cc, w;
int ma = pa->l>>1, mb = pb->l>>1; //長度除2
Node ah, al, bh, bl;
Node t1, t2, t3, t4, z;
pNode temp;
if(!ma || !mb) //如果其中個數為1
{
if(!ma) //如果a串的長度為1,pa,pb交換,pa的長度大於等於pb的長度
{
temp = pa;
pa = pb;
pb = temp;
}
ans->c = pa->c + pb->c;
w = pb->s[0];
cc = 0; //此時的進位為c
for(i=0; i < pa->l; i++)
{
ans->s[i] = (w*pa->s[i] + cc)%10;
cc= (w*pa->s[i] + cc)/10;
}
if(cc)
ans->s[i++] = cc; //如果到最後還有進位,則存入結果
ans->l = i; //記錄結果的長度
return;
}
//分治的核心
cp(pa, &ah, ma, pa->l-ma); //先分成4部分al,ah,bl,bh
cp(pa, &al, 0, ma);
cp(pb, &bh, mb, pb->l-mb);
cp(pb, &bl, 0, mb);
mul(&ah, &bh, &t1); //分成4部分相乘
mul(&ah, &bl, &t2);
mul(&al, &bh, &t3);
mul(&al, &bl, &t4);
add(&t3, &t4, ans);
add(&t2, ans, &z);
add(&t1, &z, ans);
}
int main()
{
Node ans,a,b;
cout << "輸入大整數 a:"<<endl;
cin >> sa;
cout << "輸入大整數 b:"<<endl;
cin >> sb;
a.l=strlen(sa);//sa,sb以字串進行處理
b.l=strlen(sb);
int z=0,i;
for(i = a.l-1; i >= 0; i--)
a.s[z++]=sa[i]-'0'; //倒向儲存
a.c=0;
z=0;
for(i = b.l-1; i >= 0; i--)
b.s[z++] = sb[i]-'0';
b.c = 0;
mul(&a, &b, &ans);
cout << "最終結果為:";
for(i = ans.l-1; i >= 0; i--)
cout << ans.s[i]; //ans用來儲存結果,倒向儲存
cout << endl;
return 0;
}
//program 3-4-1
#include <stdlib.h>
#include <cstring>
#include <iostream>
using namespace std;
#define M 100
char sa[1000];
char sb[1000];
typedef struct _Node
{
int s[M];
int l; //代表字串的長度
int c;
} Node,*pNode;
void add(pNode pa, pNode pb, pNode ans)
{
int i,cc,k,palen,pblen,len;
int ta, tb;
pNode temp;
if((pa->c<pb->c)) //保證Pa的次冪大
{
temp = pa;
pa = pb;
pb = temp;
}
ans->c = pb->c;
cc = 0;
k=pa->c - pb->c;
palen=pa->l + pa->c;
pblen=pb->l + pb->c;
if(palen>pblen)
len=palen;
else
len=pblen;
len=len-ans->c;
for(i=0; i<len; i++) //結果的長度最長為pa,pb之中的最大長度減去最低次冪
{
if(i<k)
ta = 0;
else
ta = pa->s[i-k];//次冪高的補0,大於低的長度後與0進行計算
if(i<pb->l)
tb = pb->s[i];
else
tb = 0;
if(i>=pa->l+k)
ta = 0;
ans->s[i] = (ta + tb + cc)%10;
cc = (ta + tb + cc)/10;
}
if(cc)
ans->s[i++] = cc;
ans->l = i;
}
int main()
{
Node ans,a,b;//ans用來儲存結果,倒向儲存
cout << "輸入大整數 a:"<<endl;
cin >> sa;
cout << "輸入大整數 a的次冪:"<<endl;
cin >> a.c;
cout << "輸入大整數 b:"<<endl;
cin >> sb;
cout << "輸入大整數 b的次冪:"<<endl;
cin >> b.c;
a.l=strlen(sa);//sa,sb以字串進行處理
b.l=strlen(sb);
int z=0,i;
for(i = a.l-1; i >= 0; i--)
a.s[z++]=sa[i]-'0'; //倒向儲存
z=0;
for(i = b.l-1; i >= 0; i--)
b.s[z++] = sb[i]-'0';
cout << "a=";
for(i = a.l-1; i >= 0; i--)
cout << a.s[i];
cout << "*10^"<<a.c;
cout << endl;
cout << "b=";
for(i = b.l-1; i >= 0; i--)
cout << b.s[i];
cout << "*10^"<<b.c;
cout << endl;
add(&a, &b, &ans);
cout << "最終結果為:";
for(i = ans.l-1; i>=0; i--)
cout << ans.s[i]; //ans用來儲存結果,倒向儲存
cout << "*10^"<<ans.c;
cout<<endl;
return 0;
}