维护按字母顺序排列的链表
Posted
技术标签:
【中文标题】维护按字母顺序排列的链表【英文标题】:Maintaining an alphabetically organized linked list 【发布时间】:2016-06-07 14:26:24 【问题描述】:我正在学习 c++,并试图按字母顺序维护一个链表。如果我要输入一个名字列表,比如“Mary, bob, sally, larry, david, roger”,我希望他们打印出(遍历列表后)“bob, david, larry, mary, roger, sally”。任何帮助将不胜感激。谢谢!
注意:当我尝试执行代码时,它没有按字母顺序打印名称。抱歉,我以为是我写的,但显然我没有。它编译得很好,但产生的结果不是预期的。
编辑:我注意到一些有趣的事情。当我尝试构建文件 c:/mingw/bin/../lib/gcc/mingw32/4.9.3/../../../../mingw32/bin/ld.exe: cannot open output file Program18ContactList.exe: Permission denied collect2.exe:error: 1d returned 1 exit status
时收到错误消息,它运行,但是当我尝试重建任何更改时,我收到了该消息。我明白这意味着什么,但不确定如何解决它。我没有删除任何源文件。我正在使用最新版本的 Eclipse Mars.2
主要
//Contact list playing with classes
//Contact lists
#include "ContactList.H"
using namespace std;
int main()
ContactList* cl1 = new ContactList();
string name;
while(true)
cout << "Enter the name of the contact or q to quit." << endl;
cin >> name;
if(name == "q")
break;
cl1->insert(name);
cl1->printList();
return(0);
类
//contact list class
#include "ContactList.H"
using namespace std;
ContactList::ContactList():head(0), size(0)
void ContactList::addToHead(const string& name)
Contact* newOne = new Contact(name);
if(head == 0)
head = newOne;
else
newOne->next = head;
head = newOne;
size++;
void ContactList::printList()
Contact* tp = head;
while(tp != 0)
cout << *tp << endl;
tp = tp->next;
void ContactList::insert(const string& name)
Contact* newNode = new Contact(name);
// case 1 - empty list
if(head == 0)
//assigns new node to the empty list head node
head = newNode;
else
//current pointer initialized to the head so as to start traversal
// trail pointer initialized to zero, but will iterate one step behind
// current to keep former data location on the stack organized
Contact* curr = head;
Contact* trail = 0;
// Traverse list to find insert location
while(curr != 0)
if(curr->name >= newNode->name)
break;
else
trail = curr;
curr = curr->next;
// case 2 - insert at head (not empty)
if(curr == head)
newNode->next = head;
head = newNode;
else
// case 3 - insert after the head (not empty)
newNode->next = curr;
trail->next = newNode;
size++;
【问题讨论】:
看看std::list 和::std::sort。不过,您可能必须使用x.compare(y) < 0
将比较器传递给std::sort。
@Aconcagua:对于实际代码,可以使用 std::vector 并在插入后对其进行排序,或者使用 std::lower_bound 保持排序。这显然是针对学生的练习 - 因此使用标准库会破坏练习的意义。
我看不出您的代码有什么问题,但处理列表时的一般规则是没有特殊情况。因此,从Contact **target = head;
开始搜索列表(如果有)以查找插入新元素的位置,并在不跳出循环时设置target = &curr->next
,然后设置newNode->next = curr; *target = newNode
。这将处理 1. 空列表; 2. 插入头部。 3.插入中间。
啊,可能到目前为止我们都遗漏了一点:operator<
、operator>
、operator<=
、operator>=
都区分大小写!因此,由于大写字母的 ascii 代码比小写字母小,这将导致“Zebra”在 before“ant”... @ 无济于事,除非您向他们提供自定义的、不区分大小写的比较器。
@StormsEdge 你不需要关闭你的IDE,你需要关闭你的可执行文件的进程,它被命名为Program18ContactList.exe
,因为你提供了最新的编辑显示的错误消息。可能还有一个正在运行的实例,因此 Windows 对其保持文件锁定并且链接器无法访问它,正如错误消息所说的那样。只要这种情况持续存在,您将无法重新编译您的程序,因此您将继续收到错误消息(“存在!继续?”)。
【参考方案1】:
到目前为止,您的列表似乎运行良好。但是请注意,调用 addToHead
会破坏排序。当然,您没有这样做,但是您提供了一个能够破坏列表的预期功能(正在排序)的界面。最好完全忽略它。
您最有可能遇到的问题是operator>=
区分大小写,因此"Zebra"
将不 被认为大于或等于"ant"
(if(curr->name >= newNode->name) break;
),因此@987654326 @ 将排在 "Zebra"
后面,因为 ascii 'Z' (90) 小于 ascii 'a' (97)。
您可以提供我们自己的操作符(至少必须在insert
的定义之前声明):
bool operator>=(std::string const& x, std::string const& y)
std::string::iterator ix = x.begin();
std::string::iterator iy = y.begin();
while(ix != x.end() && iy != y.end())
if(toupper(*ix) > toupper(*iy))
return true;
if(toupper(*ix) < toupper(*iy))
return false;
// both strings are equal so far...
// at least one string is at its end
//
// if iy is, then y is not longer than x and thus
// lexicographically not larger than x (so x is larger or equal)
return iy == y.end();
这很有效,幸运的是,std::string 的运算符实际上是模板,所以这个运算符在重载决议中具有优先权。
附注:这绝对适用于 ascii,并且适用于大多数语言(如果使用单字节编码)。但是,e 存在一些问题。 G。土耳其语,如果使用 utf-8,您可能会遇到问题。现在可能超出范围,但您可能会记得将来......
我个人倾向于认为“Alpha”大于“alpha”,“bEta”大于“beTA”,......(与 ascii 代码相反!) - 但实际上,只是口味问题。不过,您可以通过将return iy == y.end();
替换为:
if(iy != y.end())
return false;
if(ix != x.end())
return true;
return x <= y; // opposite, see above... if you agree with ascii, use >=, of course
【讨论】:
以上是关于维护按字母顺序排列的链表的主要内容,如果未能解决你的问题,请参考以下文章