将元素插入到log(n)中的已排序链接列表中

时间:2018-02-01 15:14:15

标签: c++ sorting linked-list

是否可以将元素插入到正确位置的有序链表中,而不必在O(n)中遍历它?

我需要找到元素添加到列表中的中位数和总和的中位数和总和。

我的实现依赖于一个中心处理程序,它在添加项目时会移动但在处理100000以上的数据集时仍然太慢(特别是由于插入while循环)。

在没有优先级队列或BST的情况下,还有其他方法可以解决这个问题吗?

代码:

#include <bits/stdc++.h>

using namespace std;

struct node
{
    long int data;
    node *next;
    node *prev;
};

class l_linked {
private:
    node *head, *tail, *center;
    int size = 0; 
    int left = 0, right = 0;


    void movePivot() {
        if (right > left && size%2) {
            center = center->next; // Move right
            right--;
            left++;

        }else if (right < left){
            center = center->prev; // Move right
            right++;
            left--;
        }

    }

public:

    void create_node (long int value) {
        node *temp = new node;
        temp->data = value;
        temp->next = NULL;
        temp->prev = NULL;
        if (head == NULL) {
            // If list is empty, use temp as the head and tail. 
            head = temp;
            tail = temp;
            center = temp;
            temp = NULL; // set temp to reference NULL
            size++;
        }
    }

    l_linked () {
        head = NULL;
        tail = NULL;
    }

    int getSize () {
        return size;
    }

    long int getMedian () {
        if (size%2) {
            // odd number 
            //cout << center->data << endl;
            return center->data;
        }else {
            node* temp = new node;
            temp = center->next;
            //cout << "Even: " << center->data <<  endl;
            return ((center->data + temp->data)/2);
        }
    }


    void print () {
        node *temp = new node;
        temp = head;
        while (temp != NULL) {
            cout << temp->data << " ";
            temp = temp->next;  // set temp to reference the next node. 
        }

        cout << endl;
        cout << center->data << endl;

    }

    void print_back() {
        node *temp = new node;
        temp = tail;
        while (temp != NULL) {
            cout << temp->data << " " ;
            temp = temp->prev;
        }
        cout << endl;
        cout << center->data << endl;
    }

    void insert_sort(long int input) {
        if (input > tail->data) {
            node *temp = new node;
            temp->data = input;
            temp->next = NULL;
            temp->prev = tail;
            tail->next = temp;
            tail = temp;
            size++;
            right++;
            movePivot();
            return;
        }
        else if (input < head->data){
            node *temp = new node;
            temp->data = input;
            temp->next = head;
            temp->prev = NULL;
            head->prev = temp;
            head = temp;
            size++;
            left++;
            movePivot();
            return;
        }
        // Function below seems to take up too much time 


        node *temp = new node; // Use this for traversal 
        node *insertion = new node; // Use this for insertion 
        insertion -> data = input;
        temp = head;
        int flag = 0;
        if (input > center->data) {
            temp = tail; // start from tail 
            flag = 1;
        }
        while (temp != NULL) {

            if (flag) {

                if (input > temp->data) {
                    insertion->prev = temp->prev;
                    insertion->next = temp;

                    temp->prev->next = insertion;
                    temp->prev = insertion;
                    size++;
                    if (insertion->data >= center->data) {
                        right++;
                        movePivot();
                        // Move up the pivot (upwards biased)
                    }
                    else if (insertion->data < center->data) {
                        left++;
                        movePivot();
                        // Move down the pivot 
                    }

                    return;
                }

                temp = temp->prev;

            }else {

                    if (input < temp->data) {
                        insertion->prev = temp->prev;
                        insertion->next = temp;

                        temp->prev->next = insertion;
                        temp->prev = insertion;
                        size++;
                        if (insertion->data >= center->data) {
                            right++;
                            movePivot();
                            // Move up the pivot (upwards biased)
                        }
                        else if (insertion->data < center->data) {
                            left++;
                            movePivot();
                            // Move down the pivot 
                        }

                        return;
                    }
                    temp = temp->next; // Traverse forward
            }
        }
    }


};


int main(int argc, char const *argv[])
{
    int numCase;
    cin >> numCase;
    clock_t start, end;

    for (int i = 0; i < numCase; ++i)
    {
        l_linked myList;
        int num;
        long int med = 0;
        cin >> num;

        int c = 0;
        /**
        for (int d = 0; d < num; ++d)
        {
            long int input;
            cin >> input;
            if (!d) {
                myList.create_node(input);
                med += myList.getMedian();
                continue;
            }
            myList.insert_sort (input);
            med += myList.getMedian();

        }
        */
        for (int d = 0; d < num; ++d)
        {
            start = clock();
            //long int input;
            //cin >> input;
            if (!d) {
                myList.create_node(rand() + 1);
                med += myList.getMedian();
                continue;
            }
            myList.insert_sort (rand() + 1);
            med += myList.getMedian();
            end = clock();
            if (((double)end - start) / CLOCKS_PER_SEC > 0.001)
                cout << (((double)end - start) / CLOCKS_PER_SEC) << endl;


        }

        cout << med << endl;
        //myList.print();
    }
    return 0;
}

编辑:

#include <iostream>
#include <queue>
#include <vector>
#include <functional>


using namespace std;

int main () {
    int num, numCases;
    cin >> numCases;
    clock_t start, end;
    for (int d = 0; d < numCases; d++) {
        cin >> num;
        long int median = 0;
        long int center = 0;
        priority_queue<long int> q; // Left sub tree
        priority_queue<long int, std::vector<long int>, std::greater<long int> > q2; // Right sub tree

        start = clock();

        for (int i = 0; i < num; i++) {
            long int number;
            //cin >> number;
            if (i == 0) center = rand();


            else if (number < center) {
                q.push(rand());
            }
            else if (number >= center) {
                q2.push(rand());

            }
            if (q2.size() > q.size() && (i+1)%2) {
                q.push(center);
                center = q2.top();
                q2.pop();
            } else if (q2.size() < q.size()){
                q2.push(center);
                center = q.top();
                q.pop();
            }

            if (i%2) {
                // if odd
                median += (center + q2.top())/2;
                continue;
            }

            median += (center);
            //cout << center << endl;
        }
        end = clock();

        cout << (((double)end - start) / CLOCKS_PER_SEC) << endl;

        cout << median << endl;
    }
    return 0;
}

我决定使用优先级队列。这适用于log(n)

1 个答案:

答案 0 :(得分:4)

您可以针对此问题使用skip list结构。它们的工作方式是,它们提供了一些额外的指针,以跳过列表的某些部分,以附加层的形式。这增加了空间复杂性但提高了时间复杂度通过适当的安排,我认为你应该能够达到O(logN)平均复杂度,但是最糟糕的情况是O(N)复杂度。