C++快速排序,有 2 个要求

C++ quicksort with 2 requirements

本文关键字:快速排序 C++      更新时间:2023-10-16

我的目标是根据两个标准对单词列表进行排序:

  • 主要标准是增加字长,
  • 次要标准是字母顺序

例如:

{red,a,three,b,four,aeoli}

应排序为:

{a,b,red,four,aeoli,three}.

我有两个单独的快速排序:一个是关于长度的,另一个是按字母顺序的。

我只是好奇如何将这两者合并? 我遇到的主要问题是我不知道如何在考虑长度并浏览整个列表的同时按字母顺序排序。

任何建议都值得赞赏,以下代码是我的主要代码和快速排序功能:

Vector<String> words;
String word;
ifstream inFile;
inFile.open("practice.txt");
while(!inFile.eof()){
getLine(inFile,word);
words.push_back(word);
}
inFile.close();
String pivot = "qog";
if(words[2] < pivot)
cout << "Bigger" << endl;
words.quicksort(2,words.length()-2);
words.quicksort2(2,words.length()-2);

长度的快速排序

template <typename T>
void Vector<T>::quicksort(int left, int right)
{
int i = left;
int j = right;
String pivot = data[(left+right)/2];
if(i <= j)
{
while(data[i].getLength() < pivot.getLength())
i++;
while(pivot.getLength() < data[j].getLength())
j--;
}
if(i <= j)
{
String temp = data[i];
data[i] = data[j];
data[j] = temp;
i++;
j--;
}
if(left < j)
quicksort(left,j);
if(i < right)
quicksort(i,right);
}

和字母的那个

template <typename T>
void Vector<T>::quicksort2(int left, int right)
{
int i = left;
int j = right;
String pivot = data[(left+right)/2];
if(i <= j)
{
while(data[i] < pivot)
i++;
while(pivot < data[j])
j--;
}
if(i <= j)
{
String temp = data[i];
data[i] = data[j];
data[j] = temp;
i++;
j--;
}
if(left < j)
quicksort2(left,j);
if(i < right)
quicksort2(i,right);

}

注意:这是用我自己的自定义 Vector 和 String 类完成的,两个版本都能完美运行,所以我的主要问题是排序本身的逻辑——如何让它们一起运行。

此外,我只能使用iostream,fstream和cstring,以及我自己实现的任何其他内容。

提前谢谢。

只需使用std从合理的实现向后工作,重新实现(削减)您使用的东西的版本。

sort(vec.begin(), vec.end(), [](auto & lhs, auto & rhs){ return tie(lhs.size(), lhs) < tie(rhs.size(), rhs); });

然后我们需要实现tuplesorttie

struct tuple
{
const int & first;
const String & second;
};
bool operator<(const tuple & lhs, const tuple & rhs)
{
if (lhs.first < rhs.first) return true;
if (rhs.first < lhs.first) return false;
return lhs.second < rhs.second;
}
tuple tie(const int & first, const String & second)
{
return { first, second };
}

然后,我们可以调整您的Vector::quicksort实施

template <typename Iter, typename Comp>
void quicksort(Iter left, Iter right, Comp comp)
{
auto distance = (right - left) / 2
Iter l = left;
Iter pivot = left + distance;
Iter r = right;
if(l <= r)
{
for(;comp(*l, *pivot); ++l);
for(;comp(*pivot, *r); --j);
}
if(i <= j)
{
String temp = *i;
*i = *j;
*j = temp;
++i;
--j;
}
if(left < j)
quicksort(left, j, comp);
if(i < right)
quicksort(i, right, comp);
}

或者我们可以改为查看此问答,并实现partitionfind_if_not

template<class FwdIt, class Compare = std::less<>>
void quick_sort(FwdIt first, FwdIt last, Compare cmp = Compare{})
{
auto const N = distance(first, last);
if (N <= 1) return;
auto const pivot = *next(first, N / 2);
auto const middle1 = partition(first, last, [=](auto const& elem){ 
return cmp(elem, pivot); 
});
auto const middle2 = partition(middle1, last, [=](auto const& elem){ 
return !cmp(pivot, elem);
});
quick_sort(first, middle1, cmp); // assert(std::is_sorted(first, middle1, cmp));
quick_sort(middle2, last, cmp);  // assert(std::is_sorted(middle2, last, cmp));
}
template<class ForwardIt, class UnaryPredicate>
ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
first = find_if_not(first, last, p);
if (first == last) return first;
for (ForwardIt i = next(first); i != last; ++i) {
if (p(*i)) {
iter_swap(i, first);
++first;
}
}
return first;
}
template<class InputIt, class UnaryPredicate>
constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q)
{
for (; first != last; ++first) {
if (!q(*first)) {
return first;
}
}
return last;
}
template<class InputIt>
void iter_swap(InputIt a, InputIt b)
{
using value_type = typename InputIt::value_type;
value_type temp = static_cast<value_type&&>(*a); // aka std::move
*a = static_cast<value_type&&>(*b);
*b = static_cast<value_type&&>(temp);
}
template<class T>
void iter_swap<T*>(T * a, T * b)
{
T temp = static_cast<T&&>(*a); // aka std::move
*a = static_cast<T&&>(*b);
*b = static_cast<T&&>(temp);
}
template<class InputIt>
InputIt next(InputIt it, int distance)
{
return it + distance;
}

我想最终,你会希望它按单词的最小值排序。 短单词的"价值"比长单词少,因为字母的重量小于单词,我会按每个单词的总ASCII值对其进行排序。 在这种情况下,您不需要使用 2 个排序和合并,计算每个对象的 ascii 值并按它排序。

如果必须将两种算法链接在一起,对于学校作业或其他什么,则需要实现稳定分区(或使用 std::stable_partition)。

编辑 - 阅读您的"注释"后,我应该提到安抚老师的另一种方法是实现第三个版本的快速排序,该版本在谓词中使用这两个条件。请参阅下面的shorter_less。更好的是,将谓词作为函数指针传递到单个统一的快速排序中,就像 std::sort 和 std::stable_sort 那样。 即...

这是一次性完成所有操作的C++方法...

#include <string>
#include <algorithm>
#include <vector>
using std::string;
static bool shorter_less( const string& L, const string &R) {
if (L.length() == R.length()) return L<R;
else return L.length() < R.length();
}
int main() {
using str_vec = std::vector<string>;
str_vec vec{ "xxzy" , "Alphonse", "Betty", "pea", "nuts", "z" };
std::sort(vec.begin(), vec.end(), shorter_less);
}