【问题标题】:Merge sort with insertion function带插入功能的归并排序
【发布时间】:2020-05-05 22:36:35
【问题描述】:

我有两个排序的链表 l1 和 l2。我想在保持 l1 排序的同时将 l2 合并到 l1 中。我的 return 语句是 l1 排序的, l2 是一个空列表。如何使用 insert_before、insert_after 和 remove_node 函数来解决这个问题?有什么想法吗?

【问题讨论】:

标签: algorithm data-structures merge linked-list mergesort


【解决方案1】:

如果您知道链表是​​如何实现的,那么您可以使用类似下面的方法轻松地遍历这两个列表。如果您不太了解链表,您可能需要先阅读这些内容。

if(l1 == null || l2 == null){
    return l1==null ? l2 : l1;
indexA = indexB = 0;
elemA = l1.get(0);
elemB = l2.get(0);
while(indexA<l1.size() || indexB<l2.size()){   
    if(indexA==l1.size()){
        l1.insert_after(l1.size()-1,elemB);
        indexA++;
        indexB++;
        if(indexB<l2.size()){
            elemB = l2.get(indexB);
        }
        continue;
    }
    if(indexB==l2.size()){
        break;
    }
    if(elemA<elemB){
        indexA++;
        if(indexA<l1.size()){
            elemA = l1.get(indexA);
        }
        continue;
    }
    if(elemA>elemB){
        l1.insert_before(indexA,elemB);
        indexA++;
        indexB++;
        if(indexB<l2.size()){
            elemB = l2.get(indexB);
        }
}
return l1;

这是一个类似于 java 的实现,它遍历两个列表并将它们合并在一起。我决定只返回 l1 ,因为空列表有点没用,对吧?所有低效的 get() 调用都可以通过编写自己的简单 LinkedList 类来访问下一个和最后一个字段来避免,这将极大地方便导航。

如果您可以提供有关您可用的方法或必须使用的语言的更多信息,我可能会为您提供更好的解释。

编辑:解释


首先 elemA /elemB 都被赋予链表中第一个元素的值,然后使用 while 循环遍历它们,直到用于跟踪我们在列表中的位置的索引值都太高(例如==列表大小)

现在前两个 if 语句用于检查其中一个列表是否已经完全迭代,如果第一个列表是这种情况,则第二个列表的下一个元素只是添加到 l1 的最后一个元素之后,因为它必须大于它,否则 indexA 不会增加。 (在这个 if 语句中 indexA 也会增加,因为列表的大小越来越大,并且 indexA 与 l1.size() 进行比较),最后 continue 语句跳到循环的下一次迭代。
while 循环中的第二个 if 语句测试第二个列表是否已经完全迭代,如果这是真的,就没有更多的东西可以合并,所以循环被 break 语句停止。

下面或多或少是经典的归并排序;
如果 l1 的当前元素小于 l2 的当前元素,则转到 l1 的下一个元素并进行循环的下一次迭代,否则将 l2 的当前元素插入 elemA 之前并进一步迭代这里 indexA 也递增,因为否则它不再指向正确的元素,因为在它之前插入了一个元素。
够了吗?

编辑:添加测试如果任何一个列表为空,如@itwasntme 建议的那样

【讨论】:

  • 语言是 C 语言。空列表有点重要,因为测试用例会检查这一点。你能解释一下算法吗?
  • 在这种情况下,我猜你可以只返回一个额外的空对象?
  • 如果输入列表已排序,那么如果其中任何一个可能为空,只需检查一个或另一个是否为空并立即返回另一个。
【解决方案2】:

问题中没有明确定义函数 insert_before、insert_after 和 remove_node。那么假设其中一个参数是对“列表”的引用,那么另一个参数是索引、迭代器还是指向节点的指针?如果列表是双向链表,那么第二个参数是迭代器或指向节点的指针是有意义的(每个节点都有指向前一个节点的指针,因此无需根据索引进行扫描以查找先验节点)。

对于 Visual Studio 的 std::list::sort,它使用迭代器和 std::list::splice 在列表中移动节点,使用迭代器在合并期间跟踪子列表的开始和结束种类。 std::list::sort 使用的 std::list::splice 版本将 remove_node 和 insert_before 组合成一个函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 2021-02-03
    • 2021-11-03
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多