如何将插入排序转换为O(n logn)算法?

时间:2015-04-07 13:40:30

标签: c algorithm sorting insertion-sort

我编写了以下函数,该函数在创建排序的字符串序列时计算字符串的重复实例。然而它很慢,然后我意识到这是O(n ^ 2)。所以我想把它做成O(n logn),但我不知道如何继续。有没有已知的方法将这种n ^ 2算法转换为nlogn?如何转换呢?

void insert (struct listNode **ptr, char *value) {
    struct listNode *newPtr;
    int cmp;

    // find a place to instert node to LL
    while(*ptr){
        // Comparision to detect & remove duplicates nodes

        cmp = strcmp(value, (*ptr)->data);
        // duplicate
        if(cmp == 0){
            (*ptr)->occurrence++;
            return; 
        }
        // the point where i need to add the node
        if(cmp < 0) 
            break;

        ptr = &(*ptr)->next;
    }

    // now here *ptr points to the pointer that i want to change
    // it can be NULL, if we are at the end of the LL

    newPtr = malloc(sizeof *newPtr);
    if(!newPtr)
        return;

    newPtr->data = strdup(value);
    newPtr->occurrence = 1;

    if(newPtr->data == NULL){
        free(newPtr);
        return;     
    }

    // here we are connecting our brand new node to the LL
    newPtr->next = *ptr;
    *ptr = newPtr;
}

struct listNode {
    char *data;
    struct listNode *next;
    int occurrence;
};

5 个答案:

答案 0 :(得分:3)

  

是否有任何已知方法可将此类n 2 算法转换为n * log n

如果您繁殖的两个n中的一个来自访问线性数据结构(例如您的链接列表),则可以改进为n * log n转向更快的数据结构,例如平衡的二叉树。

这将转换为使用二叉树中的搜索替换while循环搜索(线性),该搜索是日志n

答案 1 :(得分:0)

插入排序是一种单独的排序技术。如果你convert(according complexity)这个,它将是另一种排序技术。 我认为link Sorting Algorithmfind different type complexity of sorting technique有帮助。

答案 2 :(得分:0)

插入排序具有最坏情况时间O(N2)。我建议使用另一种具有Theta(n lg n)时间复杂度的算法,例如合并排序,而不是试图改变 stable 算法的时间复杂度。

让我们得到一些有用的信息,这些信息可能会帮助人们了解如何将此类问题的时间复杂性降低到Theta(n lg n)。

通常,您可以使用分而治之技术来减少排序问题的时间复杂度到Theta(n lg n)。

让我们一起理解这种算法设计范式。

分而治之

这个想法是,如果你将一个敌人分成小块,每一块,从而可以征服敌人。当应用于计算机问题时,分而治之三包括三个步骤。

  • 将问题划分为类似于原始但尺寸较小的子问题
  • 通过递归求解来解决子问题。如果它们足够小,只需要以简单的方式解决它们。
  • 合并解决方案以创建原始问题的解决方案

使用分而治之进行排序

事实证明这是非常容易的,它可能是令人惊讶的,它是渐近最优的。关键的观察是合并两个排序列表的速度很快(时间与列表大小呈线性关系)。步骤是

  • 除(带停止条件):如果S有零个或一个元素,只需返回S,因为它已经被排序。否则S有n≥2个元素:将S的第一个⌈n/2⌉元素移入S1,将剩余的⌊n/2⌋元素移入S2。
  • 递归求解:递归地对两个子序列中的每一个进行排序。
  • 组合:将两个(现已排序的)子序列合并回S

合并排序的运行时间T(n)

  • 除以:计算中间需要Theta(1)
  • 征服:解决2个子问题需要2T(n / 2)
  • 合并:合并n个元素需要Theta(n) 总计:

    如果n = 1,则T(n)= Theta(1) 如果n> 1,则T(n)= 2T(n / 2)+ Theta(n)。 1

    =&GT; T(n)= Theta(n lg n)

enter image description here

有关更多信息和示例,请查看此link

答案 3 :(得分:0)

通常,您不会通过重新编写现有算法来提高其复杂性,而是从一开始就将其设计为高效。无论如何,让我们玩这个游戏。

算法的工作原理是保持N第一个元素的列表,按排序顺序排列,并逐个合并其余元素。这种方法的成本很高,包括对排序列表O(N)进行线性搜索,总计O(N²)进行排序。

众所周知,通过二分查找,可以在O(Log(N))的时间内更有效地搜索排序列表。不幸的是,这适用于数组(用于随机访问),但是数组需要O(N)次插入。这种困境的解决方案很久以前就被发现是(平衡的)二叉树数据结构,它允许快速搜索和快速插入。

另一种不太明显的方法是尝试减少插入次数。实际上,如果您一次插入多个元素,并按排序顺序排列这些元素,则可以在一次传递中完成插入:这称为合并操作。

正如@ChakerMallek详细说明的那样,如果将列表拆分为两半,则将它们分开排序,全局排序相当于合并,并按时完成O(N)。两个子列表的排序可以递归地完成,导致众所周知的MergeSort,非常适合于链表表示并且最佳地有效。它甚至可以适应在近乎排序的列表上更快。

答案 4 :(得分:0)

如果我正确阅读,您使用的是插入排序,其复杂度为O(n ^ 2)。但是,如果在查找阶段(while循环)切换到二进制搜索,则可以在O(nlogn)中执行此操作。