对字符串数组进行自定义排序

Custom Sort on an array of Strings

本文关键字:自定义 排序 字符串 数组      更新时间:2023-10-16

给定一个包含彩虹七种颜色但按随机顺序排列的字符串数组,我应该以某种方式对该数组进行排序,以输出红色、橙色、绿色,。。。。,按顺序排列的是紫罗兰。彩虹颜色的顺序。如何对此数组进行排序?

您应该编写一个自定义比较器。以下是我的做法。

//somewhere in initalization code;
std::map<string, int> mapOrder;
mapOrder["red"] = 1;
mapOrder["orange"] = 2;
...
mapOrder["violet"] = 7;

bool isRainbowLess(const std::string& a, const std::string& b)
{
return mapOrder[a] < mapOrder[b];
}

int main()
{
std::vector<std::string> myVector;
....
std::sort(myVector.begin(), myVector.end(), &isRainbowLess);
}

此代码尚未完成。但你应该了解大致情况。我跳过的一件事是整数本身的排序。既然它应该是琐碎的。正如你所看到的,映射有点PIA,看起来很糟糕。但由于您禁止使用STL,因此没有std::map。此外,我对所有表都隐含了N的静态大小。它可以动态分配,没有问题,也没有std::vector

我对map*函数使用了else ifs来模拟std::map函数。也许可以使用switch ... case,但它在一个不错的编译器上的工作原理应该基本相同。

我在下面写的代码在提供的功能方面与Armen的代码几乎相同。我会推荐他的解决方案。我跳过了相同的部分。所以你可以看到它更丑,更打字。它看起来几乎像纯C。如果你真的渴望在非常大的情况下达到速度,也许可以进行一次修改。这将使用一个临时数据结构来保存映射的值,对其进行排序,然后将其映射回。确切地说,我建议在高性能约束下避免在std::string上调用map::operator[](const &T)(或任何访问器),以避免哈希计算。但仅此而已。

还有一些问题需要讨论。比如,如果你想让两种颜色具有相同的值,或者使用非整数权重。基于STL的解决方案适应性更强。

/* This will map color literals (color names) to integers, which will associate them with 
a numerical value, than can be used for comparison */
enum Colors { Red, Orange, Green, /*...*/ Violet };
/* this should read colors as std::string instances from the input array and assing
the the appropriate color codes into output array at corresponding indexes     */
void mapString2Color( const std::string* input, int* output, size_t N ){
for(size_t i = 0; i < N; i++){
if ( input[i] == std::string("red") ) output[i] = Colors::Red;
else if ( input[i] == std::string("orange") ) { output[i] = Colors::Orange; }
else if ( input[i] == std::string("green") )  { output[i] = Colors::Green;  }
/*...*/
else if ( input[i] == std::string("violet") ) { output[i] = Colors::Violet; }
else {/*unspecified color code */}
}
}
/* this is supposed to do the opposite to mapString (i.e. put appropriate 
string at output[i] based on input[i])  */
void mapColor2String( const int* input, std::string* output, size_t N ){
for(size_t i = 0; i < N; i++){
if ( input[i] == Colors::Red ) output[i] = std::string("red");
else if ( input[i] == Colors::Orange ) { output[i] = std::string("orange"); }
else if ( input[i] == Colors::Green  ) { output[i] = std::string("green");  }
/*...*/
else if ( input[i] == Colors::Violet ) { output[i] = std::string("violet"); }
else {/*unspecified color index*/}
}
}
void sort(int* array, size_t N){
/* any in-place sort of your liking for table of (unsigned) integers */
}
main(){
std::string[N] input_array;
std::string[N] output_array;
int[N] temp_array;
//map (translate) colors to their numerical values
mapString2Color(input_array, temp_array, N);
//sort it
sort(temp_array, N);
//map (translate) the values back to color names
mapColor2String(temp_array, output_array, N);
}

我要做的第一件事就是创建一个映射。您可以通过映射或线性迭代预排序的字符串数组并获取匹配条目的索引来实现这一点。一个非常简单的方法(实际上是为了演示的目的)可能只是将逻辑编码为一个封装的函数,如下所示:

int intForCol( const string& col ) 
{
if ( col == "red" ) return 0; 
else if ( col == "orange" ) return 1;
else if ( col == "yellow" ) return 2;
else if ( col == "green" ) return 3;
else if ( col == "blue" ) return 4;
else if ( col == "indigo" ) return 5;
else if ( col == "violet" ) return 6;
throw "Invalid colour"; 
}

这将提供一个基于输入字符串的排序整数。下一步是创建一个比较器:

int colComp( const string& lhs, const string& rhs )
{
return intForCol( lhs ) - intForCol( rhs );
}

如果lhs<rhs,如果lhs>rhs则为阳性

现在,它可以相对容易地在STL中使用,既可以作为关联容器中的比较器,也可以直接在排序算法中使用。或者,如果使用STL是不可能的,或者这是为了了解排序是如何工作的,你可以像下面的简单且(非常)低效的算法一样实现自己的排序:

const int col_size = 7;
string input[col_size];
input[0] = "indigo";
input[1] = "green";
input[2] = "red";
input[3] = "blue";
input[4] = "yellow";
input[5] = "violet"; 
input[6] = "orange";
// simple bubble sort
int passes = col_size;
int last = col_size; 
while ( passes-- )
{
for ( int i = 0; i < last - 1; ++i ) 
if ( colComp( input[i], input[i+1] ) > 0 )
{
string temp = input[i]; input[i] = input[i+1]; input[i+1] = temp;
}
last--;
}