给定一个包含 n 个元素的数组 A[1..n],其中仅有红、白、蓝三种元素。请设计一种时间复 杂度为 O(n) 的算法将数组 A 中的元素其分为三段,第一段仅包含红色元素,第二段仅包含白色 元素,最后一段仅包含蓝色元素。你设计的算法仅能通过交换数组中两个元素来对数组进行修改,并仅能使用 1 个额外空间来存储数组元素 (因此不能通过统计三种颜色的元素个数来对数组 A 进行分段)。请分析你设计的算法是否稳定。
C++实现:
#include <iostream>
using namespace std;
void SelectColor_1(int [], int );
void SelectColor_2(int [], int );
int main()
{
int arr[6] = {1,0,1,2,2,0};//Test Array
cout<<"Before:";
for(int i=0; i<6; i++)
cout<<arr[i]<<", ";
cout<<endl;
SelectColor_1(arr,6);
cout<<"After :";
for(int i=0; i<6; i++)
cout<<arr[i]<<", ";
cout<<endl;
cout << "Program end!" << endl;
return 0;
}
void SelectColor_1(int arr[], int n) //while循环实现
{
int j = -1;
int k = n;
int i = 0;
while(i < k-1)
{
if(arr[i] == 0)
{
swap(arr[i], arr[++j]);
}
else if(arr[i] == 2)
{
swap(arr[i], arr[--k]);
}
else
++i;
}
}
void SelectColor_2(int arr[], int n) //for 循环实现
{
int j = -1; //左扩充指针
int k = n;
for(int i = 0; i < n; i++)
{
if(arr[i] == 0) //若为红色,则将其与j的后一位交换
{
swap(arr[++j], arr[i]);
i--;//回溯一位,因为for循环的自动i++(也可以在for循环中把第三个条件去掉)
}
else if(arr[i] == 2) //同理,若为蓝色,则将右扩充指针的前一位与当前元素交换
{
swap(arr[--k],arr[i]);
i--;
}
if(i == k-1) //停止条件,当遍历下标等于右扩充指针时,排序完成
break;
}
}