【问题标题】:Sorting a list of structs by an element按元素对结构列表进行排序
【发布时间】:2015-05-12 09:48:08
【问题描述】:

我有一个如下结构:

struct Man 
{
  string surname;
  string name;
  char sex;
  int birth_year;
  int age;
  Man * next;
};

如何按姓氏字母顺序对列表进行排序?

我知道如何使用数组进行冒泡排序,但无法使用列表处理:/

【问题讨论】:

  • 您指的是什么“列表”? std::vector?
  • @m.s.他将结构定义为单链表的一个节点。
  • std::sort 浮现在脑海中。你有没有试过,如果有,问题是什么?如果这是一个 DIY 链表,请考虑将数据复制到标准容器并使用 std::sort 对其进行排序。如果你不想这样做,例如这是一个练习,好吧,试试merge stort。这对只进序列很有好处。
  • @Cheers 和 hth。 - Alf 他不能为他的列表应用 std::sort。
  • @VladfromMoscow:你可能是对的。不过,我可以。 ;-)

标签: c++ list sorting struct


【解决方案1】:

为了使std::list::sort 工作,您需要做的就是重载类的< 运算符。

在你的情况下,这看起来像这样

//n.b. untested code
bool operator< (const Man& other)
{
    toupper(this->surname) < toupper(other->surname);
}

你也可以调用sort 的重载,它接受一个comp 函数作为参数。见here

【讨论】:

  • @Nagendra NR 你能解释一下他如何将 std::sort 应用于他的列表吗?!
【解决方案2】:

只是建议,如果你只想排序的是姓氏,你可以尝试首先按姓氏的顺序添加这个节点,那么你不需要再次排序,因为它是通过排序完成的

【讨论】:

  • 我想按姓氏对整个结构进行排序
  • 然后你可以在添加的时候进行排序,就像你有一个“a,c”,你可以直接插入到它的中间。您可能需要'strcmp'的功能,并学习添加到列表顶部和列表中间
【解决方案3】:

使用 std::map,将列表中的每个元素插入到此映射中,姓氏作为键,Man 的对象作为值。 MAp 的元素是根据键排序的,因此只需遍历映射以按排序顺序获取对象。

【讨论】:

  • 他的任务是不使用地图直接对列表进行排序。
【解决方案4】:
  1. 您必须为您的项目创建 std::vector 或 std::deque。
  2. 使用 std::sort。

例子:

std::vector<Man*> people;
Man* head = YOUR HEAD POINTER;
// Create vector from your list
while(head) { 
     people.push_back(head);
     head = head->next;  
} 
// sort vector
std::sort(people.begin(),people.end(), [](const Man* m1, const Man* m2) {
    return m1->surname < m2->surname;
});

【讨论】:

  • 当他的任务是创建一个列表时,为什么他必须创建std::vector或std:;deque?!
  • 排序列表比向量慢。也许他有充分的理由使用您的列表而不是 std::list。
【解决方案5】:

要对列表进行排序,您可以通过在现有列表的新列表中按顺序插入元素,从现有列表构建一个新列表。

这是一个简化的例子。当然,您需要添加更多功能,例如删除列表中所有节点的功能。

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <tuple>

struct Man 
{
    std::string surname;
    std::string name;
/*
    char sex;
    int birth_year;
    int age;
*/
    Man * next;
};

void push_front( Man * &head, const std::string &surname, const std::string &name )
{
    head = new Man { surname, name, head }; 
}

std::ostream & display( const Man *head, 
                        std::ostream &os = std::cout,
                        const char *delim = ", ")
{
    for ( const Man *tmp = head; tmp; tmp = tmp->next )
    {
        os << tmp->surname << ' ' << tmp->name << delim;
    }

    return os;
}

void sort( Man * &head )
{
    Man *new_head = nullptr;

    while ( head != nullptr )
    {
        Man *node = head;
        head = head->next;

        Man *prev = nullptr;
        for ( Man *tmp = new_head; 
              tmp && !
              ( std::tie( node->surname, node->name ) < std::tie( tmp->surname, tmp->name ) ); )
        {
            prev = tmp;
            tmp = tmp->next;
        }            

        if ( prev == nullptr )
        {
            node->next = new_head;
            new_head = node;
        }
        else
        {
            node->next = prev->next;
            prev->next = node;
        }
    }

    head = new_head;    
}

int main() 
{
    Man *head = nullptr;

    std::srand( ( unsigned int )std::time( nullptr ) );

    const size_t N = 10;

    for ( size_t i = 0; i < N; i++ )
    {
        push_front( head, 
                   std::string( 1, 'A' + std::rand() % ( 'Z' - 'A' + 1 ) ),
                   std::string( 1, 'A' + std::rand() % ( 'Z' - 'A' + 1 ) ) );
    }

    display( head ) << std::endl;

    sort( head );

    display( head ) << std::endl;

    return 0;
}

程序输出是

Y P, D X, K J, R G, K J, X V, V I, X M, C K, A Y, 
A Y, C K, D X, K J, K J, R G, V I, X M, X V, Y P, 

您可以简单地比较两个节点的姓氏,而不是函数std::tie

考虑到最好将您的结构分成两部分。例如

struct Man 
{
    std::string surname;
    std::string name;
    char sex;
    int birth_year;
    int age;
};

struct Node 
{
    Man person; 
    Node * next;
};

【讨论】:

    猜你喜欢
    • 2012-09-10
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 2017-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-26
    相关资源
    最近更新 更多