2012-04-06 41 views
7

Tôi đang tìm cấu trúc dữ liệu (giống mảng) cho phép chèn nhanh các giá trị vào trong cấu trúc (nhanh hơn O (N)). Cấu trúc dữ liệu phải có khả năng in ra các phần tử của nó theo cách chúng được chèn. Điều này tương tự như một cái gì đó như List.Insert() (mà là quá chậm vì nó phải thay đổi mọi phần tử trên), ngoại trừ tôi không cần truy cập hoặc xóa ngẫu nhiên. Chèn sẽ luôn nằm trong kích thước của 'mảng'. Tất cả các giá trị là duy nhất. Không cần thao tác nào khác.Cấu trúc dữ liệu hiệu quả để chèn

Ví dụ: nếu Chèn (x, i) chèn giá trị x vào chỉ mục i (0-lập chỉ mục). Sau đó:

  • Insert (1, 0) cho {1}
  • Insert (3, 1) cho {1,3}
  • Insert (2, 1) cho {1,2,3}
  • Insert (5, 0) cho {5,1,2,3}

Và nó sẽ cần để có thể in ra {5,1,2,3} ở cuối.

Tôi đang sử dụng C++.

+0

ý bạn là gì bởi "mảng như"? – juanchopanza

+0

Bạn có yêu cầu về độ phức tạp của việc vượt qua cấu trúc dữ liệu không? –

+0

@juanchopanza Tôi có nghĩa là trên bề mặt, nó sẽ hoạt động như một mảng tuyến tính. Nó nên giữ cho các yếu tố theo cách mà tôi đã chèn chúng. – Peter

Trả lời

9

Sử dụng skip list. Một tùy chọn khác phải là tiered vector. Danh sách bỏ qua thực hiện chèn tại const O (log (n)) và giữ các số theo thứ tự. Vectơ tầng hỗ trợ chèn trong O (sqrt (n)) và một lần nữa có thể in các phần tử theo thứ tự.

EDIT: mỗi bình luận của amit tôi sẽ giải thích làm thế nào để bạn tìm thấy những yếu tố thứ k trong một danh sách bỏ qua:

Đối với mỗi yếu tố bạn có một tháp trên các liên kết đến các yếu tố tiếp theo và cho mỗi liên kết bạn biết bao nhiêu yếu tố nó nhảy qua. Vì vậy, tìm kiếm phần tử thứ k bạn bắt đầu với phần đầu của danh sách và đi xuống tháp cho đến khi bạn tìm thấy một liên kết nhảy qua không có nhiều phần tử k nữa. Bạn đi đến nút được trỏ đến bởi nút này và giảm k với số lượng phần tử bạn đã nhảy qua. Tiếp tục làm như vậy cho đến khi bạn có k = 0.

+1

Tôi cũng nghĩ đến việc bỏ qua danh sách bỏ qua, bạn có thể giải thích cách bạn sửa đổi danh sách liên kết truy cập [những người đảm bảo tìm kiếm 'O (logn)' sau khi chèn một phần tử vào vị trí tùy ý không? Nó sẽ không cần phải thay đổi rất nhiều trong số họ? Tôi tin rằng nó [bỏ qua danh sách] có thể được sửa đổi để phù hợp ở đây, nhưng điểm này nên được xây dựng IMO – amit

+0

Không có trong thực tế cách tôi đã thực hiện bỏ qua danh sách một trong khi trước đây bạn không bao giờ thay đổi cao của một nút.Điều này dựa trên thực tế là nếu bạn chèn mỗi nút mới với chiều cao phân bố đồng đều thì chiều cao của các phần tử sẽ đủ gần với các phần tử hoàn hảo. Có một số phân tích trên internet về sự phức tạp phân bổ của phương pháp này cho thấy nó không tồi tệ hơn nhiều sau đó là tốt nhất có thể. –

+0

Những gì tôi không hiểu là làm thế nào để sửa đổi không phải chiều cao, nhưng cũng có chỉ số, làm thế nào bạn có thể cho biết các yếu tố là k'th? Nếu "khóa" của bạn là các chỉ mục, thì mỗi lần chèn tùy ý sẽ yêu cầu thay đổi toàn bộ đuôi của danh sách được liên kết? [nó không phải là chiều cao mà lo lắng cho tôi, bằng cách sử dụng danh sách liên kết không xác định giải quyết vấn đề này gọn gàng] – amit

1

Bạn có cân nhắc sử dụng std::map hoặc std::vector?

Bạn có thể sử dụng số std::map với thứ hạng chèn là khóa. Và vector có chức năng thành viên reserve.

+1

OP muốn nhanh hơn sau đó chèn tùy ý tuyến tính, sẽ không vector và bản đồ là cả O (n)? – amit

+0

Có, 'std :: vector' chèn vào vị trí' i' sẽ là O ('n') vì các phần tử' i' đến 'n' cần phải được dịch chuyển. Với 'std :: map', một cái gì đó tương tự xảy ra vì các khóa phải được cập nhật. –

+0

@Yavar: Nhưng bạn sẽ phải sửa đổi các chỉ số của tất cả các yếu tố sau sau mỗi lần chèn. giả sử bạn có bản đồ = [(1, a), (2, b), (3, c)] và bạn muốn thêm z vào vị trí 0, bạn sẽ cần sửa đổi bản đồ thành [(1, z), (2, a), (3, b), (4, c)]. Nếu có giải pháp thay thế - cần được xây dựng .. – amit

-1

Trong C++ bạn chỉ có thể sử dụng bản đồ về vectơ, như vậy:

int main() { 
    map<int, vector<int> > data; 
    data[0].push_back(1); 
    data[1].push_back(3); 
    data[1].push_back(2); 
    data[0].push_back(5); 
    map<int, vector<int> >::iterator it; 
    for (it = data.begin(); it != data.end(); it++) { 
    vector<int> v = it->second; 
    for (int i = v.size() - 1; i >= 0; i--) { 
     cout << v[i] << ' '; 
    } 
    } 
    cout << '\n'; 
} 

này in:

5 1 2 3 

Cũng giống như bạn muốn, và chèn là O (log n).

+2

Nó sẽ thất bại nếu bạn tiếp tục cố gắng đẩy 10 trong chỉ mục thứ 2. – amit

1

Bạn có thể sử dụng các cặp ánh xạ (chỉ mục, thời gian chèn) std::map với giá trị, trong đó thời gian chèn là số nguyên "tự động" (trong thuật ngữ SQL).Trật tự trên các cặp nên

(i, t) < (i*, t*) 

iff

i < i* or t > t* 

Trong mã:

struct lt { 
    bool operator()(std::pair<size_t, size_t> const &x, 
        std::pair<size_t, size_t> const &y) 
    { 
     return x.first < y.first || x.second > y.second; 
    } 
}; 

typedef std::map<std::pair<size_t, size_t>, int, lt> array_like; 

void insert(array_like &a, int value, size_t i) 
{ 
    a[std::make_pair(i, a.size())] = value; 
} 
+0

Giả sử chúng ta chèn 300 tại 0, sau đó 100 tại 0, sau đó 200 tại 1. Điều gì sẽ xảy ra: '[]' rồi '[300]', sau đó '[100 300]', sau đó '[100 200 300]'. Nhưng những gì thực sự xảy ra: '[]', sau đó '[((0, 1), 300)]', sau đó '[((0, 2), 100), ((0, 1), 300)]', cho đến nay rất tốt, nhưng sau đó '[((0, 2), 100), ((0, 1), 300), ((1, 3), 200)]'. Kết luận: không có thống kê thứ tự, loại điều này thường khó làm. –

1

Về nhận xét của bạn:

List.Insert() (đó là quá chậm vì phải thay đổi mọi phần tử),

Danh sách không thay đổi giá trị của chúng, chúng lặp qua chúng để tìm vị trí bạn muốn chèn, hãy cẩn thận những gì bạn nói. Điều này có thể gây nhầm lẫn cho người mới như tôi.

0

Giải pháp được bao gồm trong GCC theo mặc định là cấu trúc dữ liệu dây. Đây là số documentation. Thông thường, dây thừng đến với tâm trí khi làm việc với các chuỗi ký tự dài. Ở đây chúng tôi có int s thay vì ký tự, nhưng nó hoạt động giống nhau. Chỉ cần sử dụng int làm thông số mẫu. (Cũng có thể là pair s, v.v.)

Đây là description of rope on Wikipedia. Về cơ bản, đó là cây nhị phân duy trì số lượng phần tử trong các subtrees trái và phải (hoặc thông tin tương đương, được gọi là thống kê đơn đặt hàng) và các số này được cập nhật một cách thích hợp khi các phụ đề được xoay khi các phần tử được chèn vào và loại bỏ. Điều này cho phép các hoạt động O (lg n).

Các vấn đề liên quan