【问题标题】:Sort linked list [duplicate]排序链表[重复]
【发布时间】:2014-02-13 22:53:37
【问题描述】:

我必须从文件中读取数据包,并按照block_num的顺序将数据包重构为链表。

struct packet {
    unsigned short  block_num;
    unsigned short  block_size;
    unsigned short  crc;
    unsigned char  *payload;
};

struct list {
    struct packet p;
    struct list *next;
};

这是我读取数据包并将它们添加到链表中的代码,但是我将如何根据 block_num 对它们进行排序?

FILE *infp;

struct list *head = NULL;
struct list *last = NULL;

while (fread(&p, sizeof(p), 1, infp) != NULL) {
    packet *newpacket = malloc(sizeof(p));

    struct list *newlist = malloc(sizeof(list));
    newlist -> p = newpacket;
    newlist -> next = NULL;

    if (head == NULL) {
        head = last = newlist;
    } else {
        last -> next = newlist;
        last = newlist;
    }
}

【问题讨论】:

  • @Smac89 不,他不是。阅读代码。 newList 是指向 newList 对象实例的指针,而不是整个列表。
  • 你试过编译上面的代码吗?那里有很多错误,您可能应该先清理一下。例如newlist -> p = newpacket这一行,其中newpacket是指针类型,但newlist->p不是。
  • 如果你收集所有的数据包然后对它们进行排序,数组比链表更好。如果您希望每个数据包在到达时插入正确的位置,那么您可能需要考虑一个(平衡的)树结构。如果数据包按顺序或多或少但不完全按顺序到达,则“平衡”很重要。在这两者中,我可能会使用一个动态增长的数组,后跟qsort()。如果你坚持,你可以把struct list结构的数组做成数组,当数据排序后,可以把数组转换成列表。

标签: c linked-list


【解决方案1】:

您希望输出是一个链表,其成员根据 block_num 排序。在这种情况下,为什么不将您的阅读功能转换为智能阅读器。

逻辑如下:

  1. 如果列表为空,请照常操作,将 head 和 last 全部分配给 newList。
  2. 如果列表不为空,首先查看遍历列表以找到当前对象的位置。在该点操作列表并连接节点。例如:

`

for (cur = head; cur != end; cur = cur->next) {
    if (cur->p->block_num <= newpacket->block_num &&
        cur->next->p->block_num > newpacket->block_num) {
        // insert newlist here
        newlist->next = cur->next;
        cur->next = newlist;
    }
}

`

在上面的代码中,cur的类型是struct list *。

【讨论】:

  • 这是一个很好的第一次尝试类型的实现,但我要补充一点,它有一个糟糕的最坏情况运行时(如果 block_num 随着每个数据包的读取而增加)。一个更有效的实现(尽管更复杂并且可能为此过度杀伤力)是在读取整个文件后运行一些快速排序算法(例如,快速排序)。
  • 这实际上是在读取时执行的插入排序,已知其时间复杂度为 O(N^2)。较大的输入速度很慢。更大的问题是您的代码无法处理极端情况。您应该对此提出警告。
  • @unluddite 是的,运行时间很糟糕。我只是给 OP 一个方向。他应该先了解如何完成,然后开始分析代码。这是要检查运行时的时候。
  • @Palec 我故意遗漏了边界守卫。正如我所说,这应该是一个广泛的逻辑和一个例子,说明在阅读过程中如何做事情。它不是读取期间的插入排序,而是插入排序本身。另外,我知道运行时间。请参阅我的其他评论。
【解决方案2】:

您必须实现自己的排序,因为标准 qsort() 仅适用于数组。我推荐merge sort

您也可以使用数组而不是链表——然后您可以使用qsort()。如果您不知道要读取的数据包数量,只需将数组的大小调整为以前的两倍,每次它已满并且您想存储另一个数据包时。那么最后添加一项的摊销时间复杂度是O(1)。

【讨论】:

    【解决方案3】:

    首先你忘了把你从文件中读取的内容复制到列表的新元素中,在 malloc 之后,你应该放:

    *newpacket = p;
    

    并且您应该在 while 循环之外声明 newpacket。然后以这种方式在链表中按顺序插入(为了简单起见,我只考虑block_num,我从键盘而不是从文件中获取它,并在按下CTRL+D时停止):

    unsigned int block_num;
    struct list *newlist;
    struct list *x, *t;
    
    while(scanf("%u", &block_num) == EOF) {
        newlist = (struct list *)malloc(sizeof(struct list));
        newlist->p.block_num = block_num;
        newlist->next = NULL;
    
        if(head == NULL) {
            /* empty list */
            head = newlist;
            last = newlist;
        }
        else {
            if(head->p.block_num > newlist->p.block_num) {
                /* insert as first element */
                newlist->next = head;
                head = newlist;
            }
            else {
                t = head;
                x = head->next;
                while(x != NULL && x->p.block_num < newlist->p.block_num) {
                    t = x;
                    x = x->next;
                }
                /* insert */
                t->next = newlist;
                newlist->next = x;
                if(x == NULL)
                    last = newlist;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-04-23
      • 2018-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-12
      • 2013-04-28
      • 2012-01-29
      • 2019-09-18
      相关资源
      最近更新 更多