案例4
荷蘭國旗問題。只包含0,1,2的整數數組進行排序,要求使用交換、原地排序,而不是利用計數進行排序。
分析:本題主要過程與快排劃分過程類似。時間複雜度O(N),空間複雜度O(1)。
如圖,一次檢查,爲0,就和首位交換,然後0區喫一個數;爲2,就和末位交換,然後2區喫一個數。檢查到二區域位置,整個過程結束。
#include<iostream>
#include<vector>
using namespace std;
void out(vector<int> arr,int n){ //數組輸出
for(int k=0;k<n;k++){
cout<<"arr["<<k<<"]:"<<arr[k]<<endl;
}
}
void sort(vector<int> &arr, int length){
int k=length-1;//後面數組位置記錄點
int temp;
int j=0;//前面數組位置記錄點
for(int i=0;i<=k;i++){//i爲當前點
if(arr[i]==0){
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
j++;
}
if(arr[i]==2){
temp=arr[i];
arr[i]=arr[k];
arr[k]=temp;
k--;
i--;//關鍵點!!!!與後面數組交換時,位置點保持不動
}
}
}
int main(){
int num;
vector<int>arr;
cout<<"荷蘭國旗"<<endl;
int n = 0;//n表示輸入個數
while (cin >> num){
arr.push_back(num);
n++;
if(cin.get() == '\n') //遇到回車,終止
break;
}
sort(arr,n); //排序
out(arr,n); //輸出數組
}
案例5
在行列都排行序的矩陣中找數
0 1 2 5
2 3 4 7
4 4 4 8
5 7 7 9
若k爲7,返回true;若k爲6,返回false。
若矩陣爲(m*n),該題最優解可以做到時間複雜度O(m+n),額外空間複雜度O(1)。
方法,從右上角找。
看5,5大於3,向左;
看2,2小於3,向下;
以此方法,找。找到,true。找到越界,false。
#include<iostream>
#include<vector>
using namespace std;
bool sort(int **arr, int row,int line,int num){
int i=0;
int j=line-1;
while(i<row&&j>=0){
if(arr[i][j]>num){
j--;
}
else if(arr[i][j]<num){
i++;
}
else if(arr[i][j]==num){
cout<<i<<" "<<j;//若能找到,輸出行列的位置
return true;
}
}
return false;
}
int main(){
cout<<"請輸入二維數組長和寬"<<endl;
int row,line;//定義行列
cin>>row>>line;
int **arr=new int*[row]; //根據行數動態分配數組行大小
for(int i=0;i<row;i++){
arr[i]=new int[line];//根據列數動態分配數組列大小
}
cout<<"請輸入二維數組"<<endl;
for(int i=0;i<row;i++)
for(int j=0;j<line;j++)
cin>>arr[i][j];
cout<<"輸出二維數組"<<endl;
for(int i=0;i<row;i++){
for(int j=0;j<line;j++)
cout<<arr[i][j]<<" ";
cout<<endl;
}
cout<<"請輸入需要找的數"<<endl;
int num;
cin>>num;
bool result=sort(arr,row,line,num);
if(result==true)
cout<<"TRUE"<<endl;
else
cout<<"FALSE"<<endl;
}
案例6
需要排序的最短子數組長度
1 5 4 3 2 6 7
返回4,因爲只有5 4 3 2需要排序。
該題最優解可以做到時間複雜度O(N),額外空間複雜度O(1)。
方法:從左向右遍歷整個數組。
首先,從左向右遍歷,記錄最大值,只關係右邊數比左邊數小的這種情況。然後記錄發生這種情況的最右位置。對此題,max=7,最右位置=2。
下從右往左遍歷,記錄最小值,和比其大的情況的最左位置。對此題,最左爲5,min=1。最左最右位置中間的數就是需要排序的最短子數組
#include<iostream>
#include<vector>
using namespace std;
void search(vector<int>arr, int length,int &max,int &right){
for(int i=1;i<length;i++){//從左向右遍歷,尋找需排序數組的右邊界
if(arr[i]>=max)
max=arr[i];
else
right=i;
}
}
void search2(vector<int>arr, int length,int &min,int &left){
for(int i=length-2;i>=0;i--){//從右向左遍歷,尋找需排序數組的左邊界
if(arr[i]<=min)
min=arr[i];
else
left=i;
}
}
int main(){
int num;
vector<int>arr;
int n = 0;//n表示輸入個數
while(cin >> num){
arr.push_back(num);
n++;
if(cin.get() == '\n') //遇到回車,終止
break;
}
int max=arr[0];
int min=arr[n-1];
int left=20;
int right=20; //左右邊界初始值,任意給定,只要兩個數相同,說明不需要排序
search(arr,n,max,right);//尋找需排序數組的右邊界
search2(arr,n,min,left);//尋找需排序數組的左邊界
if(left==right)
cout<<"不需要排序";
else
cout<<right-left+1;
}
案例7
給定一個整形數組arr,返回如果排序之後,相鄰兩數的最大差值。
例如:
1 2 3 4 7 8 9
最大是3,4 7之間
該題最優解可以做到時間複雜度O(N),額外空間複雜度O(N)。
思想來自桶排序。
解:隨機數組
7 9 3 4 2 1 8
遍歷一遍,得到min=1,max=9
總共7個數,分成7個桶。
不用考慮同一個桶的相鄰數,只用考慮桶之間的相鄰數。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int sort(vector<int>arr, int n){
vector<vector<int>> B(n+1);//定義一個二維數組,用於記錄每個桶的數,每個桶放兩個值,最大值和最小值
int max,min,i,j,maxGap;
float k;
for(i=1,max=min=arr[0];i<n;i++){//記錄數組最大值和最小值
if(arr[i]>max)
max=arr[i];
if(arr[i]<min)
min=arr[i];
}
float gap=1.0*(max-min)/n; //gap用來區分放入哪個木桶中,即桶的大小
for(i=0;i<n;i++){
k=(arr[i]-min)/gap;//很關鍵!!!先計算出值,在賦值給j(j爲int型,四捨五入)
j=k;
if(B[j].empty()){ //若爲空,該值同時賦給最大值和最小值
B[j].push_back(arr[i]);
B[j].push_back(arr[i]);
}
else{
if(B[j][0]>arr[i])
B[j][0]=arr[i];//刷新最小值
if(B[j][1]<arr[i])
B[j][1]=arr[i];//刷新最大值
}
}
for(i=j=0,maxGap=0;i<n;i=j)
{
while(B[i].empty())
i++;//若下個桶爲空,就繼續向下走
max=B[i][1];
j=i+1;
if(j<n+1)
{
while(B[j].empty())
j++;
if(j>=n+1)
break;
min=B[j][0];
if(min-max>maxGap)
maxGap=min-max;
}
}
return maxGap;//輸出結果
}
int main(){
int num;
vector<int>arr;
int n = 0;//n表示輸入個數
while(cin >> num){
arr.push_back(num);
n++;
if(cin.get() == '\n') //遇到回車,終止
break;
}
int a=sort(arr,n);//計數排序
cout<<a;
}