【问题标题】:Optimising algorithm of self-organising sequence of numbers implemented on circular doubly linked list循环双向链表上实现的自组织数列优化算法
【发布时间】:2018-06-16 08:19:09
【问题描述】:

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

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 的移动。因此,我知道什么更有效,使用 nextprev 移动它。

我已经用 50 位数字对它进行了测试,输出是正确的。迭代次数较少:

  • 无 - 13001

  • 与 - 570

它不仅没有通过一个测试,而且它对于另一个测试来说太慢了(虽然我不知道里面到底有什么,但我可以告诉你那个文件的大小在34mb)。

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

【问题讨论】:

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


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

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

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

所以你应该写一个函数而不是new

  1. 如果free_list 为NULL
    • return new List_node // 分配
  2. 其他
    • n = free_list
    • free_list = n->下一个
    • return n // 重用之前分配的节点

您应该编写一个函数,而不是 deletefree

  1. node_to_free->下一个 = free_list
  2. free_list = node_to_free // 即将节点释放到空闲列表中

这两项更改应该会给您带来显着的性能提升。如果通过测试还不够,请来寻求更多关于 SO 的建议 ;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 2018-12-16
    • 1970-01-01
    相关资源
    最近更新 更多