【问题标题】:Inserting elements into sorted linked list in log(n)将元素插入到 log(n) 中的排序链表中
【发布时间】:2018-02-01 15:14:14
【问题描述】:

是否可以将一个元素插入到正确位置的排序链表中,而不必在 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)

【问题讨论】:

  • 没有。这就是链表的本质。
  • 你尝试过 std::vector 和二分搜索吗? Big O 并不真正相关,真正的运行时才是。
  • 不要#include &lt;bits/stdc++.h&gt;,这是一个私有的非标准标头,不包含在内。
  • 您是否启用了优化器?
  • 与您的问题无关,但 insert_sort() 泄漏内存。你有这行:node *temp = new node; // Use this for traversal 后面几行是temp = head;

标签: c++ sorting linked-list


【解决方案1】:

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

【讨论】:

  • +1 用于建议仍然符合链表条件的数据结构。您应该提到搜索复杂度在平均情况下是 log N,最坏情况仍然是 O(n)
  • @AndyG 我不会说它本身就符合链表的条件,否则std::unordered_map 几乎总是也能成为链表
  • @PasserBy:为什么不呢?它是通过使用带有附加链表的链表来定义的,以使事情变得更快。
猜你喜欢
  • 2014-03-15
  • 2018-08-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2012-11-26
  • 2016-04-13
相关资源
最近更新 更多