【问题标题】:Sorting a Doubly Linked List C++对双向链表 C++ 进行排序
【发布时间】:2009-09-05 02:22:24
【问题描述】:

尝试通过遍历列表的循环来完成。

在循环中,我将头节点输入到我定义的排序函数中,然后我使用 strcmp 来确定节点中的哪个名称应该先出现。

它不起作用,因为写名字太早了。

我通过在列表中一次一个节点而不是回头查看第一个节点是否应该在最后一个节点之前来线性比较它们。解释的那部分会很有帮助。

现在对我来说最重要的两个函数定义如下: 我已经尽力去做我认为适合排序功能的事情。

void list::displayByName(ostream& out) const
{
    list *ListPtr = NULL;
    node *current_node = headByName;
    winery *wine_t = new winery(); 
    // winery is another class object type
    // im allocating it to prevent a crash when I call it.

    while ( current_node != NULL )
    {
        *(wine_t) = current_node->item;
        wine_t = ListPtr->sort( current_node );
        out << wine_t << endl;
        current_node = current_node->nextByName;
    }
    delete wine_t;
}

winery * const list::sort( node * current_node ) const
{
    // current_node is the first node.
    const char *SecondName = NULL, *FirstName  = NULL;
    winery *wine_t   = new winery();

    if ( current_node != NULL )
    {
        SecondName   = current_node->item.getName();            
        current_node = current_node->nextByName;
        FirstName    = current_node->item.getName();
    }

    if ( strcmp( FirstName, SecondName ) == -1 )
    {
        *(wine_t)  = current_node->item;
        FirstName  = NULL;
        SecondName = NULL;
        return wine_t;
    }
    else if ( strcmp( FirstName, SecondName ) == 1 )
    {
        *(wine_t) = current_node->item;
        FirstName = NULL;
        SecondName = NULL;
        return wine_t;
    }
    else return wine_t;// then the strings are equal

    FirstName  = NULL;
    SecondName = NULL;
    return wine_t;
}

我开始在这里开发我的节点:

void list::insert(const winery& winery)
{
    node *current_node = new node( winery );

    if ( headByName == NULL )
    {
        headByName   = current_node;
        headByRating = current_node;
        tail         = headByName;
        current_node->prev = current_node;
    }
    else
    {
        current_node->prev = tail;
        tail->nextByName   = current_node;
    }

    tail = current_node;
    current_node = NULL;
}

我认为它在上面的那个函数中是正确的。我可以在那里分类吗?

以下是我正在使用的变量:

public list
{
         ...
    void insert(const winery& winery);
    void displayByName(ostream& out) const;
}
private:
    struct node
    {
        node(const winery& winery);     // constructor
        winery item;
        node * prev;
        node * nextByName;
        node * nextByRating;
    };

    winery * const sort(node*) const;
    node * headByName;
    node * headByRating;
    node * tail;
};

感谢任何帮助。 非常感谢 =)

【问题讨论】:

标签: c++ sorting linked-list


【解决方案1】:

在我回答问题之前,我观察到一些您可能想要解决的问题:

  • 您的节点有两种不同的next,但只有一种prev。这真的是您想要的吗?如果是,nextprev 配对?
  • 您命名为sort 的方法不排序,而是用作比较。
  • 您似乎没有实现实际的排序(或者至少您没有在这里展示它)。
  • 不需要在sort中重复设置FirstNameSecondNameNULL。它们是局部变量,当方法返回时简单地消失。
  • sort 中不需要做两个strcmp。要么缓存第一个结果( int cmp=strcmp(...);) or use aswitchon the value returned bystrcmp`。

要对双链接数组进行排序,我会建议以下之一:

  1. 如果允许,使用支持std::sort 的标准容器(但我猜这是家庭作业,所以可能不是)。我相信std::list 符合条件。
  2. 如果排序顺序永远不会改变,则在插入时排序
  3. 实现分区排序(即quicksort),这将非常适合这种结构(但通常的示例代码是在数组上给出的,因此您必须了解正在做什么以及为什么 在链表上实现它的正确方法变得明显之前)。

【讨论】:

    【解决方案2】:

    为什么不在这里使用 std::list(STL 的双向链表)及其相关的排序函数?如果你为你的列表项定义了一个操作符

    【讨论】:

      【解决方案3】:

      据我了解,您希望list::sort 找到列表中大于输入的最小节点。

      为此,您需要遍历所有元素并保持找到当前最小但较大的节点。

      类似这样的:

      node * const list::sort( node * given_node ) const
      {
          if ( given_node == NULL )
          {
              return NULL;
          }
      
          // Smallest node found which is greater than given_node.
          node * least_found_node = NULL;
      
          // Node we are looking at right now.
          node * current_node = given_node->nextByName;
      
          // Go through all nodes.
          while ( current_node && current_node != given_node )
          {
              // Is this node bigger than the given node?
              if ( strcmp( current_node->item.getName(), given_node->item.getName() ) < 0 )
              {
                  // Is this node smaller than the smallest node we know of?
                  if ( least_found_node == NULL ||
                     ((strcmp( current_node->item.getName(), least_found_node->item.getName() ) > 0) )
                  {
                      // We found a better node.
                      least_found_node = current_node;
                  }
              }
      
              current_node = current_node->nextByName;
          }
      
          return least_found_node;
      }
      

      现在更改您的显示功能以像这样使用它:

      void list::displayByName(ostream& out) const
      {
          // Find first node initially.
          node * current_node = sort( NULL );
      
          while ( current_node != NULL )
          {
              // Print node.
              out << current_node->item.getName();
      
              // Find next node in sorted output.
              current_node = sort( current_node );
          }
      }
      

      这部分一直调用sort,直到sort返回NULL。对sort 的第一次调用是NULL,因此找到了最低的项目(即排序列表中的第一个)。如果没有比current_node 更大的节点,sort 返回NULL,从而终止循环。

      【讨论】:

      • given_node 是你所知道的最低节点。您想在排序列表中找到given_node 之后的节点。我在你如何重写你的显示函数方面犯了一个错误。我会尽快编辑我的答案。
      • 非常感谢您的帮助!它真的让我开始了。我确实必须切换第二个 if 的 strcmp 的参数来找到最低的节点名称。然而,这就是它所能找到的一切。只是第一个。它不会继续根据字母表打印其余部分。但是谢谢!这绝对让我开始了。
      • @lampshade,我的sort 函数只找到一个。您必须继续拨打sort 才能找到下一个。
      【解决方案4】:

      我不会费心编写自己的排序函数。我只会使用 qsort。由于它的接口是 c 而不是 c++,因此要使用它,您只需构建一个对象指针数组,然后使用您自己的比较器函数对其调用 qsort。然后从新排序的对象指针数组重建链表。

      【讨论】:

      • 我最终将不得不使用交换技术。链表不是非常低效吗?
      • 我忘了提到我的节点 ctor 必须接受酒厂类型作为其唯一参数...很难以这种方式制作节点可变数组..like..node **nArray = new node *[尺寸];给我一个错误:error C2440: '=' : cannot convert from 'int' to 'list::node **'
      • 你不能在任何种类的链表上使用qsort。它适用于数组。如果 OP 可以 使用数组,这是一个很好的建议,但可能还有其他限制。
      【解决方案5】:

      如果您正在为链表寻找有效的就地排序算法,请查看this one ...我发现它非常快。

      【讨论】:

        猜你喜欢
        • 2012-03-07
        • 2016-06-19
        • 1970-01-01
        • 2011-02-25
        • 1970-01-01
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多