维护按字母顺序排列的链表

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) &lt; 0 将比较器传递给std::sort。 @Aconcagua:对于实际代码,可以使用 std::vector 并在插入后对其进行排序,或者使用 std::lower_bound 保持排序。这显然是针对学生的练习 - 因此使用标准库会破坏练习的意义。 我看不出您的代码有什么问题,但处理列表时的一般规则是没有特殊情况。因此,从Contact **target = head; 开始搜索列表(如果有)以查找插入新元素的位置,并在不跳出循环时设置target = &amp;curr-&gt;next,然后设置newNode-&gt;next = curr; *target = newNode。这将处理 1. 空列表; 2. 插入头部。 3.插入中间。 啊,可能到目前为止我们都遗漏了一点:operator&lt;operator&gt;operator&lt;=operator&gt;= 都区分大小写!因此,由于大写字母的 ascii 代码比小写字母小,这将导致“Zebra”在 before“ant”... @ 无济于事,除非您向他们提供自定义的、不区分大小写的比较器。 @StormsEdge 你不需要关闭你的IDE,你需要关闭你的可执行文件的进程,它被命名为Program18ContactList.exe,因为你提供了最新的编辑显示的错误消息。可能还有一个正在运行的实例,因此 Windows 对其保持文件锁定并且链接器无法访问它,正如错误消息所说的那样。只要这种情况持续存在,您将无法重新编译您的程序,因此您将继续收到错误消息(“存在!继续?”)。 【参考方案1】:

到目前为止,您的列表似乎运行良好。但是请注意,调用 addToHead 会破坏排序。当然,您没有这样做,但是您提供了一个能够破坏列表的预期功能(正在排序)的界面。最好完全忽略它。

您最有可能遇到的问题是operator&gt;= 区分大小写,因此"Zebra" 被认为大于或等于"ant" (if(curr-&gt;name &gt;= newNode-&gt;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

【讨论】:

以上是关于维护按字母顺序排列的链表的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中使用链表按字母顺序对字符串进行排序

子程序必须按字母顺序排列。真的吗?

LinkedHashMapt深入学习

excel中怎么将英文单词按字母顺序排序?

leetcode链表--8merge-two-sorted-list(按顺序合并两个已经排好序的链表)

用单词和数字按字母顺序排列字符串