最近在學習算法,趁這個機會總結一些算法。慢慢更新,歡迎交流探討。
參考書籍:《算法導論》
排序:
輸入:n個數
輸出:有序(從大到小、從小到大)序列
一、插入排序
做排序的都需要做遍歷,而插入排序,顧名思義,就是插隊。
不必多說,給個案例體會一下:
輸入:5 4 3 2 1
處理:
- 4 5 3 2 1
- 3 4 5 2 1
- 2 3 4 5 1
- 1 2 3 4 5
輸出:1 2 3 4 5
輸入:6 8 2 4 5
處理:
- 6 8 2 4 5
- 2 6 8 4 5
- 2 4 6 8 5
- 2 4 5 6 8
代碼如下(測試):
(排序部分第11-16行);
input:輸入數組元素數n;輸入數組元素a[i];輸入n=0代碼結束;
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
int n,key,i,j,a[100];
while (cin>>n,n!=0)
{
for(int i=0;i<n;i++)
cin>>a[i];
for(int j=1;j<n;j++)
{
key=a[j];
for(i=j-1;i>=0&&a[i]>key;i--)
a[i+1]=a[i];
a[i+1]=key;
}
for(int k=0;k<n;k++)
{
cout<<a[k]<<" ";
}
cout<<endl;
}
}
二、選擇排序:
規則:首先找到數組的最小數,與a[0]交換;循環下去,找到第n小的數,與數組的第n個數交換;
案例:
輸入: 5 4 9 8 3
處理:
- 3 4 9 8 5
- 3 4 9 8 5
- 3 4 5 8 9
- 3 4 5 8 9
輸出:3 4 5 8 9
代碼如下:
#include<iostream>
using namespace std;
int main()
{
int n,a[100],key,x;
while(cin>>n,n!=0)
{
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
{
key=a[i];
x=i;
for(int j=i+1;j<n;j++)
{
if(a[j]<key)
{
key=a[j];
x=j;
}
}
int tem=a[i];
a[i]=a[x];
a[x]=tem;
}
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}
}
三、歸併排序(MERGE SORT)
規則:將原數組分解成n個子序列,再對子序列遞歸地進行排序。其中,單個元素被視爲是已經排列好的。
說明:這個算法在下根據課本先做了兩個函數,第一個是做對數組的分割,其次是對數組的排序;而在主函數中,用了srand產生100以內的隨機數。
案例:
輸入:5 2 4 7 1 3 2 6
處理:分割:5 2 4 7 1 3 2 6
合併:2 5 4 7 1 3 2 6
再合併:2 4 5 7 1 2 3 6
再合併:1 2 3 4 5 6 7
代碼如下:
#include <iostream>
#include <time.h>
#include <stdlib.h>
using namespace std;
void Merge(int *_Array, int p, int q, int r) {// p:第0個;r:第n-1個數,q:第(r + p) / 2個數
int len1 = q - p + 1;
int len2 = r - q;
int *L = new int[len1 + 1];//用動態數組儲存左邊的數
int *R = new int[len2 + 1];//用動態數組儲存右邊的數
for (int i = 0; i < len1; i++) {// 把Array數組左邊的數放入L數組
L[i] = _Array[p + i];
}
for (int j = 0; j < len2; j++) {// 把Array數組右邊的數放入R數組
R[j] = _Array[q + 1 + j];
}
L[len1]=R[len2]=INT_MAX; //定義無窮大
int i = 0, j = 0;
for (int k = p; k <= r; k++) {
if (L[i] < R[j]) {//小的放左邊,大的放右邊
_Array[k] = L[i];
i++;
}
else {
_Array[k] = R[j];
j++;
}
}
}
void MergeSort(int _Array[], int p, int r) {
if (p < r) {//p:第0個;r:第n-1個數。數組至少要有兩個數據
int q;
q = (r + p) / 2;//拆分兩組
MergeSort(_Array , p , q);//拆分第0個到第 (r + p) / 2個 ,即拆分左半部分
MergeSort(_Array , q+1 , r);//拆分第(r + p) / 2個到第r個 ,即拆分右半部分
Merge(_Array , p , q , r);//調用合併函數,從第0個到第n-1個排好
}
}
int main() {
int n;
cout<<"請輸入數組的元素數:";
cin >> n;
cout << endl;
int *Array = new int[n];
cout << "隨機數組爲:";
srand((unsigned)time(0));
for (int i = 0; i < n; i++) {
Array[i] = (rand()%(100-0+1))+0;
//cin>>;
cout<<Array[i]<<" ";
}
cout<<endl;
MergeSort(Array,0,n-1);
cout << "排序後的數組爲:";
for(int j = 0;j<n;j++){
cout<<Array[j]<<" ";
}
return 0 ;
}
四、快速排序法
- 介紹:
快速排序的最壞情況(輸入數從小到大或從大到小)的運行時間爲cita(n^2),但快速排序是用於排序的最佳實用選擇,因爲其平均性能相當好,一般的運行時間爲cita(nlgn),且cita(nlgn)中的常數因子很小。此外,快速排序還可以就地排序,在虛存環境中也能很好運行。
同歸並排序類似地,快速排序也是基於分治法的,
- divide 分解:將數組A[p....r]劃分爲兩個子數組A[p..q-1]和A[q...r]排序,使得A[p...q-1]<=A(q)<=A[q+1...r]
- conquer解決:通過遞歸調用Quicksort,對子數組A[p...q-1]和A[q...r]排序。
- combine.合併:此步可忽略,因爲A[p...r]已經排序。
- 原理:
- 案例:(來自算法導論)僅partition部分:
代碼如下:
#include<iostream>
#include<time.h>
#include<stdlib.h>
using namespace std;
int Partition(int *a,int p,int q) //函數:使得<x的數在X的左邊,>x的數在x的右邊
{
int x=a[p];
int i=p;
for(int j=p+1;j<=q;j++)
{
if(a[j]<=x)
{
i++;
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
int temp=a[i];
a[i]=a[p];
a[p]=temp;
return i;
}
void QuickSort(int *a,int p,int q)
{
if(p<q) //遞歸停止的信號p>=q
{
int r=Partition(a,p,q);
QuickSort(a,p,r-1);
QuickSort(a,r+1,q);
}
}
int main()
{
int n;
cout<<"請輸入";
cin >> n;
cout << endl;
int *Array = new int[n];
cout << "產生的隨機數組爲:";
srand((unsigned)time(0));
for (int i = 0; i < n; i++) {
Array[i] = (rand()%(100-0+1))+0;
cout<<Array[i]<<" ";
}
cout<<endl;
QuickSort(Array,0,n-1);
cout << "排序後的數組爲:";
for(int j = 0;j<n;j++){
cout<<Array[j]<<" ";
}
return 0;
}
快速排序的最佳情況運行時間爲cita(nlgn);
快速排序的最壞情況運行時間爲cita(n^2) //即是劃分得不平衡,如劃分爲n-1與1;
,而插入排序的最壞情況運行時間爲cita(n),這時候快速排序真是徒負虛名。這歸咎於我們選取的x的位置被固定住了,所以下面的隨機快速排序就是一種優化。
五、隨機快速排序
作爲一種優化,其實也是用一個隨機種子生產隨機數,隨機抽取某一個數做爲x,再調用partition函數,僅僅加了一個函數,再做一點點修改,代碼如下:
#include<iostream>
#include<time.h> //添加文件
#include<stdlib.h>
using namespace std;
int Partition(int *a,int p,int q)
{
int x=a[p];
int i=p;
for(int j=p+1;j<=q;j++)
{
if(a[j]<=x)
{
i++;
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
int temp=a[i];
a[i]=a[p];
a[p]=temp;
return i;
}
int Random_Partition(int* a,int p,int q) //產生隨機數做下標,使得中間數是隨機的數
{
int i=rand()%(q-p)+0;
int temp=a[i];
a[i]=a[q];
a[q]=temp;
return Partition(a,p,q);
}
void QuickSort(int *a,int p,int q)
{
if(p<q)
{
int r=Random_Partition(a,p,q);
QuickSort(a,p,r-1);
QuickSort(a,r+1,q);
}
}
int main()
{
int n;
cout<<"請輸入";
cin >> n;
cout << endl;
int *Array = new int[n];
cout << "產生的隨機數組爲:";
srand((unsigned)time(0));
for (int i = 0; i < n; i++) {
Array[i] = (rand()%(100-0+1))+0;
cout<<Array[i]<<" ";
}
cout<<endl;
/*cout<<"請輸入數組:"<<endl;
for(int i=0;i<n;i++)
cin>>Array[i];*/
QuickSort(Array,0,n-1);
cout << "返回的下標爲:"<<Partition(Array,0,n-1)<<endl;
cout << "排序後的數組爲:";
for(int j = 0;j<n;j++){
cout<<Array[j]<<" ";
}
delete []Array ;
return 0;
}
六、計數排序法
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
void Counting_Sort(int *a,int *b,int n,int *c,int m)
{
for(int i=0;i<m;i++)
c[i]=0;
for(int j=0;j<n;j++)
c[a[j]]++;
for(int i=1;i<m;i++)
c[i]+=c[i-1];
for(int j=n-1;j>=0;j--)
{
b[c[a[j]]-1]=a[j];
c[a[j]]--;
}
}
int main()
{
int n,m;
cout<<"input an number as the size of the matrix:"<<endl;
cin>>n;
cout<<"input the largest number you hope:"<<endl;
cin>>m;
int *a = new int[n];
int *b = new int[n];
int *c = new int[m];
cout<<"here is the matrix:"<<endl;
srand((unsigned)time(0));
for(int i=0;i<n;i++)
{
a[i]=rand()%(m+1)+0;
cout<<a[i]<<" ";
}
cout<<endl;
/*寫成函數。。
for(int i=0;i<m;i++)//注意這些循環的界限
c[i]=0;
for(int j=0;j<n;j++)
c[a[j]]++;
for(int i=1;i<m;i++)
c[i]+=c[i-1];
for(int j=n-1;j>=0;j--)
{
b[c[a[j]]-1]=a[j];
c[a[j]]--;
}*/
Counting_Sort(a,b,n,c,m);
cout<<"and the result is:"<<endl;
for(int i=0;i<n;i++)
cout<<b[i]<<" ";
cout<<endl;
delete []a; //new之後最好delete掉
delete []b;
delete []c;
}
七、基數排序法
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int GetMax(int a[],int n)
{
int max=a[0];
for (int i=0;i<n;i++)
max= a[i]>max?a[i]:max;
return max;
}
void CountingSort(int a[],int n,int exp)
{
int b[n]={0};
int c[10]={0};
for(int i=0;i<n;i++)
c[(a[i]/exp)%10]++;
for(int i=1;i<10;i++)
c[i]+=c[i-1];
for(int j=n-1;j>=0;j--)
{
b[c[(a[j]/exp)%10]-1]=a[j];
c[(a[j]/exp)%10]--;
}
for(int i=0;i<n;i++)
a[i]=b[i];
}
void RadixSort(int a[],int n)
{
int exp;
int max=GetMax(a,n);
for(exp=1;max/exp>0;exp*=10)
CountingSort(a,n,exp);
}
int main()
{
int n,m;
cout<<"please input a numb as the length of matrix:"<<endl;
cin>>n;
cout<<"please input the largest numb you hope:"<<endl;
cin>>m;
int *a = new int [n];
srand((unsigned)time(0));
for(int i=0;i<n;i++)
{
a[i]=rand()%m;
cout<<a[i]<<" ";
}cout<<endl;
RadixSort(a,n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}cout<<endl;
delete []a;
return 0;
}