我正在创建一个在插入时排序的链接列表。它是一个模板类,因此类型是在运行时定义的。
问题是,我正在比较两个值以查看哪个值最大,然后我将该值放在它应该是的链表中的位置。对于任何基于数学的类型,这都可以正常工作,但它对字符串不起作用。它不按字母顺序排序。
这是我正在尝试正常工作的代码,所以我可以比较两个字符串并找出哪一个字母顺序排在第一位(但它是一个模板,所以它也必须适用于其他类型)
比较代码在这里
while ( data > iter->_data && iter->_next != 0) {
这是完整的代码,我在下面的main()中也包含了一些代码
template <typename T>
class LinkedList;
template <class TNode>
class Iterator
{
friend class LinkedList<typename TNode::value_type>;
TNode* pNode;
Iterator(TNode* _pNode) : pNode(_pNode) {}
public:
void operator++() { pNode = pNode->_next; }
void operator++(int) { pNode = pNode->_next; }
bool operator!=(Iterator<TNode> rval) { return !(pNode == rval.pNode); }
bool operator==(Iterator<TNode> rval) { return (pNode == rval.pNode); }
typename TNode::value_type operator*() { return pNode->_data; }
Iterator<TNode> operator+(int _i)
{
Iterator<TNode> iter = *this;
for (int i = 0; i < _i; ++i)
{
if (iter.pNode) //If there's something to move onto...
++iter;
else
break;
}
return iter; //Return regardless of whether its valid...
}
};
template <typename T>
class Node
{
friend class LinkedList<T>;
friend class Iterator<Node<T> >;
Node() : _next(0) {}
Node(T data) : _data(data), _next(0) {}
Node(T data, Node<T>* next) : _data(data), _next(next) {}
Node(Node<T>* next) : _next(next) {}
T _data;
Node<T>* _next;
Node<T>* _prev;
public:
typedef T value_type;
};
template <typename T>
class LinkedList
{
Node<T>* first;
int count = 0;
public:
typedef Iterator<Node<T> > iterator;
typedef T value_type;
LinkedList() : first(0) {}
~LinkedList()
{
if (first)
{
Node<T> *iter = first;
while (iter != 0)
{
Node<T>* tmp = iter;
iter = iter->_next;
delete tmp;
}
}
}
bool LinkedList<T>::operator < (LinkedList<T> rhs);
bool LinkedList<T>::operator > (LinkedList<T> rhs);
void insert(T data)
{
if (first)
{
Node<T> *iter = first;
Node<T> *preIter = first;
while ( data > iter->_data && iter->_next != 0) {
preIter = iter;
iter = iter->_next;
}
if (iter == first) {
if (data < iter->_data) {
Node<T>* holder = first;
first = new Node<T>(data);
first->_next = holder;
holder->_prev = first;
first->_prev = 0;
}
else if (iter->_next != 0) {
Node<T>* newIter = new Node<T>(data);
newIter->_next = first->_next;
first->_prev = newIter;
newIter->_prev = first;
first->_next = newIter;
}
else {
first->_next = new Node<T>(data);
first->_next->_prev = first;
}
}
else if(preIter->_next != 0) {
Node<T>* newIter = new Node<T>(data);
preIter->_next = newIter;
newIter->_next = iter;
iter->_prev = newIter;
newIter->_prev = preIter;
}
else {
iter->_next = new Node<T>(data);
iter->_next->_prev = iter->_next;
}
}
};
iterator begin() { return iterator(first); }
iterator end() { return iterator(0); }
bool erase(iterator& _iNode) //True for success, vice versa
{
/* This is rather inneffecient. Maybe a better way to do this? */
/* Even then, it's *still* more effecient than a contiguous container */
if (_iNode.pNode == first)
{
first = first->_next;
delete _iNode.pNode;
return true;
}
else
{
for (Node<T>* iter = first; iter->_next; iter = iter->_next)
{
if (iter->_next == _iNode.pNode) //Find our node.
{
iter->_next = _iNode.pNode->_next;
delete _iNode.pNode;
return true;
}
}
}
return false;
}
};
使用以下代码,结束排序结果不等于测试。它适用于整数测试(也包括在内),但不适用于字符串测试。我在第一个A ... Z字符串测试的开始处得到所有大写字符,并且完整单词测试的一些单词不在第二个字符串测试的正确位置。一般来说,它相当准确,但不完全按字母顺序排列。
如何按字母顺序排序?
/** Test fundamental concept by storing and retrieving 0..9 */
BOOST_AUTO_TEST_CASE(ut_concept_0_to_9) {
vector<long> v{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto shuffle = v;
random_shuffle(shuffle.begin(), shuffle.end());
LinkedList<long> sl;
for (auto x : shuffle)
sl.insert(x);
auto it = sl.begin();
for (auto x : v) {
BOOST_CHECK_EQUAL(*it, x);
++it;
}
}
/** Test fundamental concept by storing and retrieving A..Z */
BOOST_AUTO_TEST_CASE(ut_concept_A_to_Z) {
string s = "Hello, world!";
LinkedList<string::value_type> sl;
for (auto ch : s)
sl.insert(ch);
sort(s.begin(), s.end());
auto it = sl.begin();
for (auto ch : s) {
BOOST_CHECK_EQUAL(*it, ch);
++it;
}
}
/** Test fundamental concept by storing and retrieving strings */
BOOST_AUTO_TEST_CASE(ut_concept_strings) {
vector<string> words{ "Sunna", "Mona", "Tiw", "Woden", "Thunor", "Frige", "Saturn" };
LinkedList<string> sl;
for (auto ch : words)
sl.insert(ch);
sort(words.begin(), words.end());
auto it = sl.begin();
for (auto word : words) {
BOOST_CHECK_EQUAL(*it, word);
++it;
}
}
编辑:我的独特解决方案
我最终发现我的问题不是纯粹的字母排序问题。它实际上在我的代码中。我错过了一种情况,我将放置我试图在最后一个对象和倒数第二个对象之间放置的对象。它应该超越最后一个对象。此代码将被清理,因为有许多区域需要清理,但这应该正确排序。我不需要按字母顺序排序。
else if (iter->_next == NULL) {
if (iter->_data < data) {
iter->_next = new Node<T>(data);
iter->_next->_prev = iter->_next;
}
else {
Node<T>* newIter = new Node<T>(data);
preIter->_next = newIter;
newIter->_next = iter;
iter->_prev = newIter;
newIter->_prev = preIter;
}
}
}
我在下面给出了答案,因为我用它来解决我的问题,这也是字母顺序的答案,这是我原来的问题。所以,最初的问题得到了解答,但我发现另一个问题导致我的这个问题对我来说无用,但其他人可能需要回答这个问题。
答案 0 :(得分:1)
正如其他人所指出的那样,std::string
重载了运算符<
和>
来完成字典比较的工作。
但是,如果您的目标是进行字母排序,那么您需要重写模板类。但是使用你已编写的代码会使事情变得非常混乱,因此可以采取不同的方法。
如果允许您使用std::list
,则可以使用包装类来编写以自定义顺序存储项目的模板链接列表类。
首先,我们需要让模板不仅采用一种类型,而且采用比较函数来告诉链表有关如何将项目插入列表的标准。
如果不解释太多,这里是代码:
#include <functional>
#include <algorithm>
#include <cctype>
#include <list>
#include <iterator>
#include <iostream>
#include <string>
template <typename T, typename Comparer = std::greater<T>>
class LinkedList
{
private:
std::list<T> m_list;
public:
void insert(const T& data)
{
Comparer comp;
typename std::list<T>::iterator it = m_list.begin();
while (it != m_list.end())
{
// call the > comparison function
if (comp(data, *it))
++it; // keep searching
else
{
// this is the spot
m_list.insert(it,data);
return;
}
}
// has to go on the end if not inserted
m_list.push_back(data);
}
// use this for demonstration purposes only
void displayMe()
{
std::copy(m_list.begin(), m_list.end(), std::ostream_iterator<T>(std::cout, "\n"));
}
};
struct MyComparerForStrings
{
// case insensitive comparison
bool operator()(const std::string& s1, const std::string& s2)
{
std::string str1Cpy(s1);
std::string str2Cpy(s2);
// convert to lower case
std::transform(str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower);
std::transform(str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower);
// returns if first string is > second string
return (str1Cpy > str2Cpy);
}
};
int main()
{
LinkedList<std::string, MyComparerForStrings> sList;
sList.insert("abc");
sList.insert("zzz");
sList.insert("joe");
sList.insert("BOB");
sList.displayMe();
cout << "\n";
LinkedList<int> intList;
intList.insert(10);
intList.insert(1);
intList.insert(3);
intList.displayMe();
}
那我们做了什么?我们创建了一个模板类,它接受两个参数,一个类型和一个比较函数。
请注意,比较默认为类型std::greater
的{{1}}。例如,如果T
是T
,那么int
将对两个整数进行比较,以查看第一项是否大于第二项。上面的示例显示,如果类型的std::greater<int>
足够(对于operator >
,则使用单个参数来实例化模板)。
但是,我们希望我们的目的是按字母顺序排序int
(或不区分大小写)。为此,我们将自定义函数作为模板参数提供,该函数采用两个字符串并按字母顺序进行比较(直到这个SO问题:Case insensitive string comparison in C++)
现在,std::string
函数使用迭代器,只使用我们的比较函数搜索点以插入项目。找到后,它只调用insert
函数,它完成所有工作。
这绝不是世界上最好的例子。但你应该能够理解。
以下是一个实例:http://coliru.stacked-crooked.com/a/ecb2e7957eb4fea8