在英国有人能解释如何做非递归归并排序工作?

由于

有帮助吗?

解决方案

通过元件环路和使通过交换两个排序两个相邻的每组时必要的。

现在,处理两组基(任意两个,最有可能的是相邻基团,但可以使用在第一和最后一个基团)将它们合并成一个组,直到所有4个元素是被重复地选择来自各组的最低值元素合并成一组4.现在,你什么都没有,但4组,再加上可能的剩余部分。使用围绕先前逻辑回路,再次做这一切除在4.该循环运行团此时工作直到只有一个组。

其他提示

非递归合并排序的工作原理是考虑1,2,4,8,16..2 ^ N在输入阵列的窗口大小。对于每个窗口(在下面的代码数“k”),窗口的所有相邻对被合并到一个临时空间,然后放回阵列。

下面是我的单一功能,基于C的,非递归的合并排序。 输入和输出都在“A”。临时存储在“B”。 有一天,我想有一个版本是就地:

float a[50000000],b[50000000];
void mergesort (long num)
{
    int rght, wid, rend;
    int i,j,m,t;

    for (int k=1; k < num; k *= 2 ) {       
        for (int left=0; left+k < num; left += k*2 ) {
            rght = left + k;        
            rend = rght + k;
            if (rend > num) rend = num; 
            m = left; i = left; j = rght; 
            while (i < rght && j < rend) { 
                if (a[i] <= a[j]) {         
                    b[m] = a[i]; i++;
                } else {
                    b[m] = a[j]; j++;
                }
                m++;
            }
            while (i < rght) { 
                b[m]=a[i]; 
                i++; m++;
            }
            while (j < rend) { 
                b[m]=a[j]; 
                j++; m++;
            }
            for (m=left; m < rend; m++) { 
                a[m] = b[m]; 
            }
        }
    }
}

顺便说,它也很容易证明这是O(n log n)的。超过窗口大小外环生长作为两种功率,所以k具有登录n次迭代。尽管存在由内环覆盖许多窗口,一起,对于给定ķ所有窗口正好覆盖输入数组,所以内循环为O(n)。组合内环和外环:为O(n)* O(log n)的= O(N log n)的

Algorithmist 引用:

  

底向上合并排序是一个   合并的非递归变种   排序,其中,所述阵列通过排序   道次的序列。在每个   通,该阵列被划分成块   的大小的。 (最初, m = 1的)。   每两个相邻块合并   (在正常归并排序),以及   下一个道次与两倍制成   的值的

两个递归和非递归合并排序具有的O相同的时间复杂度(n日志(N))。这是因为这两个方法中的一个或另一个方式使用堆栈。

在非递归方法    用户/程序员定义并使用堆

在递归的方法叠层由系统内部用来存放被递归调用的函数的返回地址

您可能需要使用非递归归并的主要原因是为了避免递归堆栈溢出。我的例子我想100万条记录进行排序,每个记录的长度(= 100千兆字节)1字节,按照字母顺序。的顺序(N ^ 2)排序将需要10 ^ 16的操作,即,它需要几十年来运行每比较操作,即使在0.1微秒。的顺序(N日志(N))合并排序将小于10 ^ 10操作或不到一小时以相同的操作速度下运行。然而,在归并的递归版本,100亿元素排序结果在50亿递归调用归并()。在每个堆叠递归几百个字节,这种溢出即使过程很容易堆内存中适合递归堆栈。这样做排序使用上我使用上述拉玛Hoetzlein提供的代码heap--动态分配的内存合并,但我用在堆上动态分配内存,而不是使用stack--我可以把1亿条记录与整理非递归归并排序,我不使栈溢出。对网站的适当的谈话“堆栈溢出”!

PS:谢谢你的代码,拉马Hoetzlein

PPS:在堆上100千兆字节!!那么,它的Hadoop集群上的虚拟堆,而归并将并行执行在多台计算机分担负载...

我是新来的。 我已经修改拉玛Hoetzlein解决方案(感谢您的想法)。我归并排序不使用最后一个副本回圈。再加上它倒在插入排序。我已经基准它在我的笔记本电脑,它是最快的。甚至比递归版本更好。顺便说这是在java和从排序按降序升序排列。当然,这是迭代。它可以进行多线程。代码变得复杂。所以,如果有兴趣的人,请看看。

代码:

    int num = input_array.length;
    int left = 0;
    int right;
    int temp;
    int LIMIT = 16;
    if (num <= LIMIT)
    {
        // Single Insertion Sort
        right = 1;
        while(right < num)
        {
            temp = input_array[right];
            while(( left > (-1) ) && ( input_array[left] > temp ))
            {
                input_array[left+1] = input_array[left--];
            }
            input_array[left+1] = temp;
            left = right;
            right++;
        }
    }
    else
    {
        int i;
        int j;
        //Fragmented Insertion Sort
        right = LIMIT;
        while (right <= num)
        {
            i = left + 1;
            j = left;
            while (i < right)
            {
                temp = input_array[i];
                while(( j >= left ) && ( input_array[j] > temp ))
                {
                    input_array[j+1] = input_array[j--];
                }
                input_array[j+1] = temp;
                j = i;
                i++;
            }
            left = right;
            right = right + LIMIT;
        }
        // Remainder Insertion Sort
        i = left + 1;
        j = left;
        while(i < num)
        {
            temp = input_array[i];
            while(( j >= left ) && ( input_array[j] > temp ))
            {
                input_array[j+1] = input_array[j--];
            }
            input_array[j+1] = temp;
            j = i;
            i++;
        }
        // Rama Hoetzlein method
        int[] temp_array = new int[num];
        int[] swap;
        int k = LIMIT;
        while (k < num)
        {
            left = 0;
            i = k;// The mid point
            right = k << 1;
            while (i < num)
            {
                if (right > num)
                {
                    right = num;
                }
                temp = left;
                j = i;
                while ((left < i) && (j < right))
                {
                    if (input_array[left] <= input_array[j])
                    {
                        temp_array[temp++] = input_array[left++];
                    }
                    else
                    {
                        temp_array[temp++] = input_array[j++];
                    }
                }
                while (left < i)
                {
                    temp_array[temp++] = input_array[left++];
                }
                while (j < right)
                {
                    temp_array[temp++] = input_array[j++];
                }
                // Do not copy back the elements to input_array
                left = right;
                i = left + k;
                right = i + k;
            }
            // Instead of copying back in previous loop, copy remaining elements to temp_array, then swap the array pointers
            while (left < num)
            {
                temp_array[left] = input_array[left++];
            }
            swap = input_array;
            input_array = temp_array;
            temp_array = swap;
            k <<= 1;
        }
    }

    return input_array;

万一有人仍然潜伏在这个线程...我已经适应上述拉玛Hoetzlein的非递归的合并排序算法,双链表排序。这种新的排序是原地的,稳定的,避免了昂贵的时间将名单码这是在其他链接列表合并排序的实现。

// MergeSort.cpp
// Angus Johnson 2017
// License: Public Domain

#include "io.h"
#include "time.h"
#include "stdlib.h"

struct Node {
    int data;
    Node *next;
    Node *prev;
    Node *jump;
};

inline void Move2Before1(Node *n1, Node *n2)
{
    Node *prev, *next;
    //extricate n2 from linked-list ...
    prev = n2->prev;
    next = n2->next;
    prev->next = next; //nb: prev is always assigned
    if (next) next->prev = prev;
    //insert n2 back into list ...  
    prev = n1->prev;
    if (prev) prev->next = n2;
    n1->prev = n2;
    n2->prev = prev;
    n2->next = n1;
}

void MergeSort(Node *&nodes)
{
    Node *first, *second, *base, *tmp, *prev_base;

    if (!nodes || !nodes->next) return;
    int mul = 1;
    for (;;) {
        first = nodes;
        prev_base = NULL;
        //sort each successive mul group of nodes ...
        while (first) {
            if (mul == 1) {
                second = first->next;
                if (!second) { 
                  first->jump = NULL;
                  break;
                }
                first->jump = second->next;
            }
            else
            {
                second = first->jump;
                if (!second) break;
                first->jump = second->jump;
            }
            base = first;
            int cnt1 = mul, cnt2 = mul;
            //the following 'if' condition marginally improves performance 
            //in an unsorted list but very significantly improves
            //performance when the list is mostly sorted ...
            if (second->data < second->prev->data) 
                while (cnt1 && cnt2) {
                    if (second->data < first->data) {
                        if (first == base) {
                            if (prev_base) prev_base->jump = second;
                            base = second;
                            base->jump = first->jump;
                            if (first == nodes) nodes = second;
                        }
                        tmp = second->next;
                        Move2Before1(first, second);
                        second = tmp;
                        if (!second) { first = NULL; break; }
                        --cnt2;
                    }
                    else
                    {
                        first = first->next;
                        --cnt1;
                    }
                } //while (cnt1 && cnt2)
            first = base->jump;
            prev_base = base;
        } //while (first)
        if (!nodes->jump) break;
        else mul <<= 1;
    } //for (;;)
}

void InsertNewNode(Node *&head, int data)
{
    Node *tmp = new Node;
    tmp->data = data;
    tmp->next = NULL;
    tmp->prev = NULL;
    tmp->jump = NULL;
    if (head) {
        tmp->next = head;
        head->prev = tmp;
        head = tmp;
    }
    else head = tmp;
}

void ClearNodes(Node *head)
{
    if (!head) return;
    while (head) {
        Node *tmp = head;
        head = head->next;
        delete tmp;
    }
}

int main()
{  
    srand(time(NULL));
    Node *nodes = NULL, *n;
    const int len = 1000000; //1 million nodes 
    for (int i = 0; i < len; i++)
        InsertNewNode(nodes, rand() >> 4);

    clock_t t = clock();
    MergeSort(nodes);    //~1/2 sec for 1 mill. nodes on Pentium i7. 
    t = clock() - t;
    printf("Sort time: %d msec\n\n", t * 1000 / CLOCKS_PER_SEC);

    n = nodes;
    while (n)
    {
        if (n->prev && n->data < n->prev->data) { 
            printf("oops! sorting's broken\n"); 
            break;
        }
        n = n->next;
    }
    ClearNodes(nodes);
    printf("All done!\n\n");
    getchar();
    return 0;
}

编辑2017年10月27日:固定影响奇数编号列表中的错误

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top