【问题标题】:Mergesort not working as intended with linked list合并排序未按预期与链表一起工作
【发布时间】:2021-11-10 03:44:24
【问题描述】:

前言:

我不关心我的特定归并排序算法的可行性。这不是问题所在。我很好奇为什么我已经编写的程序的行为方式如此,而不是为什么我应该使用 STL 或其他什么。这是为了学习目的。

问题:

我有一个由Node*s 组成的链表结构。我已经为这个特定的结构编写了一个半递归合并排序算法(我说半是因为实际排序在技术上是迭代的),但它并没有按照它应该的方式工作(升序排序)。当使用调试器遍历代码时,实际排序函数merge() 似乎不会在整个调用过程中保留新排序的列表,我无法思考如何做到这一点。谁能解释一下?

这是一个最小的可重现示例:

#include <iostream>
struct Link {
    Link(int d=int(), Link* n=nullptr) {
        data = d;
        next = n;
    }
    int         data;
    Link* next;
};

struct LinkList {
  Link* sentinel;
  size_t      size;

 LinkList(Link* h=new Link, size_t s=0) {
    size = s;
    sentinel = h;
  }

  ~LinkList() {
    Link* current = sentinel;
    while (current != 0) {
      Link* next = current->next;
      delete current;
      current = next;
    }
    sentinel = 0;
  }
};

// split into beg and end subLinkList using f/s ptr algorithm
void split(Link* sentinel, Link*& beg, Link*& end) {
    Link* s = sentinel, * f = sentinel->next;

    while (f != NULL) {
        f = f->next;
        if (f != NULL) {
            s = s->next;
            f = f->next;
        }
    }
    beg = sentinel;
    end = s->next;
    s->next = NULL;
}

// conquer (merge) elements from both subLinkLists into new sentinel
Link* merge(Link* beg, Link* end) {
    Link* sentinel = new Link;
    Link* tmp;
    for (tmp = sentinel; beg != NULL && end != NULL; tmp = tmp->next) {
        if (beg-> data < end->data) {
            tmp->next = beg;
            beg = beg->next;
        }
        else {
            tmp->next = end;
            end = end->next;
        }
    }
    if (beg == NULL)
        tmp->next = end;
    else
        tmp->next = beg;
    return tmp;
}

// recursive splitting and merging
Link* sort_merge(Link* sentinel) {
    Link* beg, * end;

    if (sentinel == NULL || sentinel->next == NULL)
        return sentinel;

    split(sentinel, beg, end);
    sort_merge(beg);
    sort_merge(end);

    return merge(beg, end);
}

// helper function calls sort_merge
void sort(LinkList &l) {
  sort_merge(l.sentinel);
}

void print(LinkList &l) {
  for (Link* n = l.sentinel; n != NULL; n = n->next) {
      std::cout << n->data << '\n';
    }
}

int main() {
  // set up linked LinkList 5->4->3->2->1->nullptr
  Link* sentinel = new Link(5 , new Link(4, new Link(3, new Link(2, new Link(1)))));
  LinkList l(sentinel,5);

  sort(l);
  print(l);

  return 0;
}

我想要的输出是

1
2
3
4
5

但它输出

5

【问题讨论】:

  • 您忽略了来自msort 的返回。这是故意的吗?
  • 哦,我不是。我想我不太清楚该怎么处理它,实际上。
  • 您实现了功能并设计了 API。返回值应该是多少?

标签: c++ pointers linked-list mergesort


【解决方案1】:

几个问题:

  1. merge 返回合并列表的 last 节点而不是第一个节点。所以改变:

    return tmp;
    

    到:

    return head->next;
    
  2. msort 中,递归调用的返回值被忽略,但它很重要,因为它表示排序操作之后的第一个节点。所以改变:

    msort(left);
    msort(right);
    

    到:

    left = msort(left);
    right = msort(right);
    
  3. sort 中,msort 的返回值被忽略,因此列表的head 引用永远不会更新。所以改变:

    msort(l.head);
    

    到:

    l.head = msort(l.head);
    

【讨论】:

  • 就是这样!非常感谢您提供令人难以置信的清晰和简洁的解释。我希望有办法报答你!
猜你喜欢
  • 1970-01-01
  • 2016-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-24
  • 2020-05-23
相关资源
最近更新 更多