是否可以将元素插入到正确位置的有序链表中,而不必在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)
答案 0 :(得分:4)
您可以针对此问题使用skip list结构。它们的工作方式是,它们提供了一些额外的指针,以跳过列表的某些部分,以附加层的形式。这增加了空间复杂性但提高了时间复杂度通过适当的安排,我认为你应该能够达到O(logN)平均复杂度,但是最糟糕的情况是O(N)复杂度。