圆形双向链表上自组织数列的优化算法

时间:2018-01-06 21:05:49

标签: c++ algorithm performance optimization linked-list

几天前我问你为我的问题挑选最好的数据结构。在那段时间里,我也解释了我的问题,并将其描述为:

Self-organising sequence of numbers with big amount of operations on it - best data structure

我已经实现了它,但不幸的是它无法通过几次测试。这是我的代码:

#include <stdio.h>
#include <stdlib.h>
using namespace std;
int allCharCounter = 0;

struct List_node{
    int value;
    struct List_node *next;
    struct List_node *prev;
};

//inserting at first
void insert(List_node** start, int v){
    List_node* newNode = new List_node;
    newNode->value = v;

    if(*start == NULL){

        newNode->next = newNode;
        newNode->prev = newNode;
        *start = newNode;
    }else{
        newNode->next = *start;
        newNode->prev = (*start)->prev;
        (*start)->prev->next = newNode;
        (*start)->prev = newNode;
    }
}

//getting input
int getNumber(){
    int c = getchar_unlocked();
    int value = 0;
    for(; (c < 48 || c > 57); c = getchar_unlocked());

    for(; c > 47 && c < 58 ; c = getchar_unlocked()){
        value = 10*value+c-'0';
        allCharCounter++;
    }
    return value;
}


int main(){

    int numberOfOperations = getNumber();
    struct List_node* list = NULL;

    //counter of numbers
    int numbersInSeq = 0;

    //passing values to list
    while(!feof(stdin)){
        int number = getNumber();
        insert(&list, number);
        numbersInSeq++;
    }

    if(list !=NULL){

        while(numberOfOperations-- != 0){
            int c = list->value;

            //insert - X
            if(c & 1){
                List_node* newNode = new List_node;
                newNode->value = c-1;

                newNode->prev = list;
                newNode->next = list->next;
                list->next->prev = newNode;
                list->next = newNode;

                numbersInSeq++;
                int moveNext = c%numbersInSeq;
                //int movePrev = numbersInSeq - moveNext;

                for(int i = 0; i < moveNext; i++){
                    list = list->next;
                }
            }else{
                //remove - R
                c = list->next->value;
                List_node* tmp = list->next;

                list->next = tmp->next;
                list->next->prev = list;
                tmp->next = NULL;
                tmp->prev = NULL;
                free(tmp);

                numbersInSeq--;
                int moveNext = c%numbersInSeq;
                //int movePrev = numbersInSeq - moveNext;
                //moving my list (POS)
                for(int i = 0; i < moveNext; i++){
                    list = list->next;
                }
            }

        }
        //printing output
        for(int i = 0; i < numbersInSeq; i++){
            fprintf(stdout, "%d",list->value); 
            if(i != numbersInSeq-1){
                fprintf(stdout, "%c",' '); 
            }
            list = list->next;
        }

    }else{
        //in case of empty list return -1
        fprintf(stdout, "%d", -1); 
    }
    fprintf(stdout, "%c",'\n');         
    fprintf(stdout, "%d",allCharCounter);

}

此代码使用循环双向链表,输出始终是正确的,但正如我之前所说,它对于某些测试来说太慢了。你也可能看到我错误地使用next实现移动列表(POS)。所以我想出了这个:

int moveNext = c%numbersInSeq;
int movePrev = numbersInSeq - moveNext;
if(moveNext < movePrev){
    for(int i = 0; i < moveNext; i++){
        list = list->next;                  
    }   
}else{
    for(int i = 0; i < movePrev; i++){
        list = list->prev;
    }
}

在X和R方法中递增和递减 numbersInSeq 后立即注入。变量 moveNext 是使用next将指针移动到所需位置所需的迭代次数。所以它的差异和 numbersInSeq 是由prev的运动。因此,我知道什么更有效,使用 next prev 移动它。

我在50个数字的例子中进行了测试,输出正确。迭代次数较小:

  • w / o - 13001

  • with - 570

不仅在那里还没有通过一次测试,但是对于另一次测试来说它太慢了(虽然我不确切知道那里有什么,但我可以告诉你那个文件它的大小约为34mb)。

也许你可以看到我在这里错过了/写得不好/不了解结构。是否有可能以某种方式优化我的代码更快?

1 个答案:

答案 0 :(得分:0)

  1. 请查看您之前的问题。您标记为正确的答案实际上是不正确的:您只需要一个单链接的循环列表,因为您总是向前移动而不是向后移动。

  2. 显然,代码中的运算符newdelete(在您的情况下为free)会影响性能。基本上,内存分配很慢,如果你想通过一些性能测试,你应该避免它。

  3. 有多种技术可以避免内存分配。最简单的方法是使用自由列表元素维护另一个free_list

    所以你应该编写一个函数来代替new

    1. 如果free_list为NULL
      • 返回新的List_node // allocate
    2. 否则
      • n = free_list
      • free_list = n-&gt; next
      • return n //重用以前分配的节点
    3. 而不是deletefree你应该写一个函数:

      1. node_to_free-&gt; next = free_list
      2. free_list = node_to_free //即将节点释放到空闲列表
      3. 这两项更改应该会为您带来显着的性能提升。如果通过测试是不够的,请在SO上提出更多建议;)