【问题标题】:Sorting a linked-list of ints in C++在 C++ 中对整数的链表进行排序
【发布时间】:2012-11-04 15:56:36
【问题描述】:

我必须创建一种按从小到大的顺序存储整数的链表。 如果您有或知道如何为链表创建排序功能,请在此处显示是否关闭和/或教我如何用 C++ 编写代码。

【问题讨论】:

  • 尝试对链表进行排序通常是个坏主意。
  • 为什么对链表进行排序是个坏主意?
  • @IrfanM:所以您实际上必须构建列表,而不是对现有列表进行排序?在这种情况下,只需插入适当的位置。我同意这听起来像是功课,不过......
  • 最近有人问了非常相似的问题。我要再次发布相同的链接,chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html 这是最好的方法,会获得最高分,但冒泡排序总比没有好。
  • 使用或排序链表不是一个坏主意。唯一的坏主意是做出类似“这通常是个坏主意......”的声明,最重要的是,您使用的数据结构取决于问题问题、预期的使用模式和可用替代方案的成本。此外,考虑到这听起来像家庭作业,我认为链表和排序是个好主意:人们需要学习和理解基本的数据结构和算法及其局限性,而最好的方法就是动手实践。现在,我要离开肥皂盒了。

标签: c++ algorithm sorting linked-list


【解决方案1】:

如果我们只是向您展示代码,我们将对您造成极大的伤害。相反,我会给你两种不同的方法,你可以实现你喜欢的一种。

第一种方法是在插入时进行“排序”:当你插入一个值时,比如 7,你按照这个过程从列表中的第一个条目开始,直到你用完节点:

如果您正在检查的节点的值大于 7,您将在您正在检查的节点之前插入一个新节点并返回。否则,您将查看下一个节点。如果没有下一个节点,则。您在列表末尾插入一个新节点,因为这意味着 7 大于列表中的所有其他条目并返回。

第二种选择是使用多种排序算法之一对整个列表进行排序。我建议您使用 BubbleSort,因为它易于理解和实现。您可以在 Wikipedia 上阅读有关冒泡排序(以及许多其他排序算法)的更多信息。

【讨论】:

  • 感谢您向我解释。
【解决方案2】:

我经常通过索引指针列表对链表进行排序。要构建一个,需要分配相当于节点数 (N) * 节点指针大小的内存。这个概念很简单。

注意:这个算法是用 C 语言编写的,因为我不完全确定 OP 是否打算将其归类为 C++ 问题(谁 hell 使用 C++ 中的链表和你的标准容器处置??)

  1. 确定列表中的节点数 (N)
  2. 为N个节点指针分配一个指针数组。
  3. 用列表中的每个节点指针加载指针数组。 IE。遍历列表,并在指针数组的每个槽中放置一个指针,并随行递增。
  4. 将此节点指针数组发送到您的排序算法(我喜欢运行时库qsort(),因为它是标准配备的)。
  5. 排序后,遍历整个指针数组(少一个),设置每个节点的“下一个”指针指向后面的那个。最后一个将其“next”指针设置为 NULL。
  6. 将头指针设置为指针数组中的第一个指针[0]。
  7. 释放指针数组的内存

您的链接列表已排序。


假设你的节点是这样的:

struct node
{
   ..data fields..
   int keyField;  // << determines sort order
   struct node *next;
};

确定列表中的节点数。我假设你有一个可以做到这一点的 proc,这很简单:

size_t list_count(struct node* head)
{
   size_t count = 0;
   while (head)
   {
      ++count;
      head = head->next;
   }
   return count;
}

分配一个与列表大小相同的指针数组,其中 nItems 是大于 1 的列表节点计数(与长度为 0 或 1 的列表无关):

struct node **ptrs = malloc(sizeof(*ptrs)*nItems);

用列表中的所有项目填充指针数组:

struct node *ptr = head;
size_t i=0;
for (;i<nItems;++i,ptr = ptr->next)
    ptrs[i] = ptr;

现在使用适当的比较功能将其发送至qsort()。下面是一个基于我们结构中的keyField 排序的比较函数示例:

int compare_node_ptrs(const void* left, const void* right)
{
    struct node *l = *(struct node**)left;
    struct node *r = *(struct node**)right;
    return l->keyField - r->keyField;
}

调用 qsort() 看起来像这样:

qsort(ptrs, nItems, sizeof(*ptrs), compare_node_ptrs);

现在遍历整个列表。重新连接“下一个”指针:

for (i=0;i<(nItems-2);++i)
    ptrs[i]->next = ptrs[i+1];
ptrs[nItems-1] = NULL;

重新连接头指针。

head = ptrs[0];

最后,释放指针数组。

free(ptrs);

您的链接列表已排序。


Sidebar 合并排序是我所知道的唯一一种 O(nlogn) 算法,它可以对链表进行排序而无需增加空间要求。一个通用的解决方案原型如下:

mergesort_list(void **head, size_t offset_ptr, int(*comp)(void*,void*))

head: address of the head pointer.
offset_ptr: offset in bytes from a node ptr where the 'link' pointer can be found.
comp: comparison function.

【讨论】:

  • 感谢您为我分解并解释每个步骤。
  • @IrfanM 没问题。我希望每一步发生的事情都有意义。
  • 我认为至少现在是这样。我会在一秒钟内实现它并让你知道。
【解决方案3】:

好老的quicksort 可以解决问题(C++03 友好):

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>

using namespace std;

void qsort(list<int>::iterator first, list<int>::iterator last)
{
    if (distance(first, last) < 2)
        return;
    int pivot = *first;

    list<int>::iterator it = partition(first, last, bind2nd(less<int>(), pivot));

    qsort(first, it);
    qsort(it, last);
}

int main()
{
    std::list<int> l;
    l.push_back(5);
    l.push_back(4);
    l.push_back(1);
    l.push_back(10);
    l.push_back(3);
    l.push_back(6);
    l.push_back(7);

    cout << "List:";
    copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, " "));
    cout << endl;

    qsort(l.begin(), l.end());

    cout << "Sorted list:";
    copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, " "));
    cout << endl;
    return 0;
}

检查:http://ideone.com/OOGXSp

【讨论】:

  • 啊,好的。我喜欢这种方法。但是我怎么能改变它,让它只有一个参数/参数,这是我的类型( Set )或需要排序的链表。
  • 如果你要从std::list开始,你可以使用内置的sort method
猜你喜欢
  • 2012-12-25
  • 1970-01-01
  • 2012-08-02
  • 2012-10-07
  • 1970-01-01
  • 2015-05-03
  • 2011-11-02
  • 2012-03-07
  • 2016-06-19
相关资源
最近更新 更多