簡體   English   中英

圓雙鏈表上數字自組織序列的優化算法

[英]Optimising algorithm of self-organising sequence of numbers implemented on circular doubly linked list

幾天前,我問過您,以便為我的問題選擇最佳的數據結構。 在那個時候,我還解釋了我的問題並將其描述為:

自組織數字序列並對其進行大量運算-最佳數據結構

我已經實現了它,但是不幸的是它不能通過幾個測試。 這是我的代碼:

#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方法中遞增和遞減numberInSeq后立即注入。 變量moveNext是通過使用next將指針移動到所需位置所需的多次迭代。 因此,它與numbersInSeq的區別前移 因此,我知道什么更有效,可以使用nextprev進行移動。

我已經用50位數字對示例進行了測試,輸出正確。 迭代次數較小:

  • 不帶-13001

  • 與-570

它不僅沒有再通過一個測試,而且對於另一個測試來說太慢了(盡管我不知道其中到底有什么,但我可以告訴你該文件的大小約為34mb)。

也許您可以在這里看到我錯過的內容/對結構的評價很差/不知道。 是否有可能以某種方式優化我的代碼以使其更快?

  1. 請查看您之前的問題。 您標記為正確的答案實際上是不正確的:您所需要的只是一個單鏈接的循環列表,因為您始終向前移動而從不向后移動。

  2. 顯然,代碼中的運算符newdelete (對於您而言是free的)對性能的影響最大。 基本上,內存分配很慢,因此如果要通過某些性能測試,則應避免使用它。

有多種技術可以避免內存分配。 最簡單的方法是維護帶有free list元素的另一個free_list

因此,您應該編寫一個函數而不是new

  1. 如果free_list為NULL
    • 返回新的List_node //分配
  2. 其他
    • n = free_list
    • free_list = n->下一個
    • return n //重用先前分配的節點

並且應該delete函數而不是deletefree

  1. node_to_free-> next = free_list
  2. free_list = node_to_free //將節點釋放到空閑列表

這兩個更改將顯着提高性能。 如果不足以通過測試,請提供更多關於SO的建議;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM