Mảng so với danh sách liên kết


200

Tại sao ai đó muốn sử dụng một danh sách liên kết trên một mảng?

Mã hóa một danh sách liên kết là, không nghi ngờ gì, công việc nhiều hơn một chút so với việc sử dụng một mảng và người ta có thể tự hỏi điều gì sẽ biện minh cho nỗ lực bổ sung.

Tôi nghĩ rằng việc chèn các phần tử mới là không đáng kể trong một danh sách liên kết nhưng nó là một việc vặt trong một mảng. Có những lợi thế khác khi sử dụng danh sách được liên kết để lưu trữ một tập hợp dữ liệu so với việc lưu trữ nó trong một mảng?

Câu hỏi này không phải là một bản sao của câu hỏi nàycâu hỏi khác đang hỏi cụ thể về một lớp Java cụ thể trong khi câu hỏi này liên quan đến các cấu trúc dữ liệu chung.


1
Liên quan - Khi nào nên sử dụng LinkedList <> over ArrayList <>? - đó là Java, nhưng mảng (ArrayList) và danh sách liên kết có lẽ có cùng hiệu suất trong bất kỳ ngôn ngữ nào.
Bernhard Barker


1
@rootTraveller Thực ra câu hỏi đó sẽ là một bản sao của câu hỏi này vì câu hỏi của tôi đã được đăng lên đầu tiên.
Onorio Catenacci

Câu trả lời:


147
  • Lưu trữ dữ liệu có kích thước khác nhau dễ dàng hơn trong danh sách được liên kết. Một mảng giả định mọi phần tử có cùng kích thước.
  • Như bạn đã đề cập, danh sách được liên kết sẽ dễ dàng phát triển hơn. Kích thước của một mảng cần phải được biết trước hoặc được tạo lại khi nó cần phát triển.
  • Xáo trộn một danh sách liên kết chỉ là một vấn đề thay đổi những gì điểm đến những gì. Xáo trộn một mảng phức tạp hơn và / hoặc chiếm nhiều bộ nhớ hơn.
  • Miễn là tất cả các lần lặp của bạn diễn ra trong bối cảnh "foreach", bạn sẽ không mất bất kỳ hiệu suất nào trong lần lặp.

19
Làm thế nào là các mặt hàng có kích thước khác nhau được đối xử khác nhau? Danh sách được liên kết sử dụng cấu trúc cố định với trường tiếp theo (yêu cầu kích thước cố định) hoặc lưu trữ một con trỏ tới dữ liệu trong xe (kích thước biến OK). Cả hai cách tiếp cận đều dễ dàng với một vectơ. Tương tự cho việc xáo trộn.
Brian

32
Tôi sẽ nói xáo trộn một mảng là ít phức tạp hơn.
Hugh Allen

23
Câu trả lời này không chính xác và sai lệch. (ngoại trừ việc cần biết kích thước của một mảng khi bạn khai báo)
Robert Paulson

35
Sẽ không lặp lại một danh sách liên kết sẽ chậm hơn vì địa phương dữ liệu?
Firas Assaad

6
@Rick, vectơ thường phân bổ không gian mà chúng yêu cầu để chúng không cần phân bổ không gian mới mỗi khi kích thước tăng lên. Kết quả là các vectơ thường tốn ít bộ nhớ hơn, không nhiều hơn các danh sách được liên kết.
Winston Ewert

179

Một lý do chính đáng khác là các danh sách được liên kết cho vay độc đáo để triển khai đa luồng hiệu quả. Lý do cho điều này là các thay đổi có xu hướng cục bộ - chỉ ảnh hưởng đến một hoặc hai con trỏ để chèn và xóa tại một phần cục bộ của cấu trúc dữ liệu. Vì vậy, bạn có thể có nhiều luồng làm việc trên cùng một danh sách được liên kết. Hơn nữa, có thể tạo các phiên bản không khóa bằng cách sử dụng các thao tác kiểu CAS và tránh các khóa nặng hoàn toàn.

Với một danh sách được liên kết, các trình vòng lặp cũng có thể duyệt qua danh sách trong khi sửa đổi đang diễn ra. Trong trường hợp lạc quan khi sửa đổi không va chạm, các trình vòng lặp có thể tiếp tục mà không có sự tranh chấp.

Với một mảng, bất kỳ thay đổi nào làm thay đổi kích thước của mảng có thể sẽ yêu cầu khóa một phần lớn của mảng và trên thực tế, rất hiếm khi điều này được thực hiện mà không có khóa toàn cầu trên toàn bộ mảng để sửa đổi trở thành vấn đề thế giới.


9
Alex - đó là một sự cân nhắc thú vị sẽ không bao giờ xảy ra với tôi. Câu trả lời rất hay. Tôi sẽ nâng bạn lên hai lần nếu tôi có thể. :-)
Onorio Catenacci

5
Hãy xem các danh sách bỏ qua (cụ thể là ConcurrencySkipListMap trong Java 6) để biết ý tưởng tốt về nơi bạn có thể đi với điều này. CSLM là một bản đồ được sắp xếp, đồng thời với hiệu suất tuyệt vời. Xa, tốt hơn nhiều so với TreeMap được đồng bộ hóa. tech.puredanger.com/2007/10/03/skip-lists
Alex Miller

Danh sách ngoại trừ đó ConcurrentSkipListMaphoặc ConcurrentSkipListMapkhông phải là danh sách, ngay cả khi Danh sách của rải xảy ra ở đâu đó trong tên của họ. Cả hai đều yêu cầu các khóa sẽ được sắp xếp và duy nhất. Nếu bạn cần một List, tức là cấu trúc dữ liệu cho phép các phần tử trùng lặp theo thứ tự tùy ý, điều đó không phù hợp và bạn sẽ phải mất nhiều thời gian để tạo cấu trúc dữ liệu giống như LinkedListmột thứ có thể cập nhật đồng thời. Nếu bạn chỉ cần một hàng đợi đồng thời hoặc deque, vâng, thậm chí có những ví dụ hiện có, nhưng một bản đồng thời Listtôi không tin rằng điều này thậm chí có thể xảy ra.
Holger

128

Wikipedia có phần rất tốt về sự khác biệt.

Danh sách liên kết có một số lợi thế so với mảng. Các phần tử có thể được chèn vào danh sách được liên kết vô thời hạn, trong khi một mảng cuối cùng sẽ lấp đầy hoặc cần phải thay đổi kích thước, một thao tác đắt tiền thậm chí có thể không thực hiện được nếu bộ nhớ bị phân mảnh. Tương tự, một mảng mà từ đó nhiều phần tử bị loại bỏ có thể trở nên trống rỗng hoặc cần phải được làm nhỏ hơn.

Mặt khác, các mảng cho phép truy cập ngẫu nhiên, trong khi các danh sách được liên kết chỉ cho phép truy cập tuần tự vào các phần tử. Trên thực tế, các danh sách liên kết đơn chỉ có thể được duyệt theo một hướng. Điều này làm cho các danh sách được liên kết không phù hợp với các ứng dụng mà việc tìm kiếm một phần tử theo chỉ mục của nó một cách nhanh chóng, chẳng hạn như heapsort. Truy cập tuần tự trên các mảng cũng nhanh hơn so với các danh sách được liên kết trên nhiều máy do lưu trữ dữ liệu tham chiếu và lưu trữ dữ liệu. Danh sách liên kết nhận được hầu như không có lợi ích từ bộ đệm.

Một nhược điểm khác của danh sách được liên kết là dung lượng lưu trữ bổ sung cần thiết cho các tham chiếu, điều này thường khiến chúng không thực tế đối với danh sách các mục dữ liệu nhỏ như ký tự hoặc giá trị boolean. Nó cũng có thể chậm và với bộ cấp phát ngây thơ, lãng phí, để phân bổ bộ nhớ riêng cho từng thành phần mới, một vấn đề thường được giải quyết bằng cách sử dụng nhóm bộ nhớ.

http://en.wikipedia.org/wiki/Linked_list


4
Đây là câu trả lời hoàn hảo. Mô tả ngắn gọn những ưu điểm và nhược điểm của cả hai.
Rick

cảm ơn bạn)) chết đơn giản nhưng tôi chưa thấy nó trên wiki)
Timur Fayzrakhmanov

58

Tôi sẽ thêm một danh sách khác - danh sách có thể hoạt động như các cấu trúc dữ liệu chức năng thuần túy .

Chẳng hạn, bạn có thể có các danh sách hoàn toàn khác nhau chia sẻ cùng một phần kết thúc

a = (1 2 3 4, ....)
b = (4 3 2 1 1 2 3 4 ...)
c = (3 4 ...)

I E:

b = 4 -> 3 -> 2 -> 1 -> a
c = a.next.next  

mà không phải sao chép dữ liệu được trỏ avào bc.

Đây là lý do tại sao chúng rất phổ biến trong các ngôn ngữ chức năng, sử dụng các biến không thay đổi - prependvà các tailhoạt động có thể diễn ra tự do mà không phải sao chép dữ liệu gốc - các tính năng rất quan trọng khi bạn coi dữ liệu là bất biến.


4
Một sự cân nhắc rất thú vị khác mà tôi sẽ không bao giờ nghĩ ra. Cảm ơn bạn.
Onorio Catenacci

Làm thế nào tôi có thể làm điều này trong python?
trao đổi quá mức

29

Bên cạnh việc chèn vào giữa danh sách dễ dàng hơn - việc xóa từ giữa danh sách được liên kết cũng dễ dàng hơn nhiều so với mảng.

Nhưng thành thật mà nói, tôi chưa bao giờ sử dụng một danh sách liên kết. Bất cứ khi nào tôi cần chèn và xóa nhanh, tôi cũng cần tra cứu nhanh, vì vậy tôi đã đi đến Hashset hoặc Từ điển.


2
Rất đúng, chèn và xóa xuất hiện sau khi tìm kiếm hầu hết thời gian, vì vậy cần phải xem xét tổng số phức tạp thời gian là tốt.
MA Hossain Tonu

28

Hợp nhất hai danh sách được liên kết (đặc biệt là hai danh sách liên kết đôi) nhanh hơn nhiều so với hợp nhất hai mảng (giả sử hợp nhất là phá hủy). Cái trước lấy O (1), cái sau lấy O (n).

EDIT: Để làm rõ, tôi có nghĩa là "hợp nhất" ở đây theo nghĩa không có thứ tự, không phải như trong sắp xếp hợp nhất. Có lẽ "concatenating" sẽ là một từ tốt hơn.


2
Chỉ khi bạn đơn giản nối thêm một danh sách vào danh sách khác. Nếu bạn thực sự hợp nhất hai danh sách được sắp xếp thì nó sẽ ghi nhật ký nhiều hơn O (1).
Herms

3
@Herms, nhưng bạn có thể hợp nhất hai danh sách được liên kết được sắp xếp mà không cần phân bổ thêm bộ nhớ, chỉ cần duyệt qua cả hai danh sách và đặt con trỏ một cách thích hợp. Hợp nhất hai mảng thường sẽ mất ít nhất một mảng.
Paul Tomblin

1
Vâng, hợp nhất danh sách là bộ nhớ hiệu quả hơn, nhưng đó không thực sự là những gì tôi đã nhận xét. Nói rằng việc hợp nhất các danh sách được liên kết là O (1) là rất sai lệch mà không làm rõ vụ việc.
Herms

Danh sách hợp nhất @Herms không hiệu quả hơn bộ nhớ so với việc hợp nhất các mảng dưới bất kỳ mô hình dữ liệu hợp lý nào.
Alexei Averchenko

2
Alexei Averchenko: Kết hợp hai danh sách, hoặc thậm chí sắp xếp hợp nhất hai danh sách được sắp xếp, có thể được thực hiện tại chỗ, với bộ nhớ O (1). Ghép nối hai mảng cần bộ nhớ O (n), trừ khi các mảng đã liền kề trong bộ nhớ. Tôi nghĩ rằng điểm bạn đang nhắm đến là trong đó một danh sách gồm n phần tử và một mảng gồm n phần tử đều chiếm bộ nhớ O (n), nhưng hệ số này cao hơn cho các danh sách được liên kết.
hung hăng

17

Một đối số không được đánh giá cao cho ArrayList và chống lại LinkedList là LinkedLists không thoải mái khi gỡ lỗi . Thời gian dành cho các nhà phát triển bảo trì để hiểu chương trình, ví dụ như tìm lỗi, tăng và IMHO đôi khi không biện minh cho các nano giây trong cải tiến hiệu suất hoặc byte trong mức tiêu thụ bộ nhớ trong các ứng dụng doanh nghiệp. Đôi khi (tốt, tất nhiên, nó phụ thuộc vào loại ứng dụng), tốt hơn là lãng phí một vài byte nhưng có một ứng dụng dễ bảo trì hơn hoặc dễ hiểu hơn.

Ví dụ, trong môi trường Java và sử dụng trình gỡ lỗi Eclipse, việc gỡ lỗi một ArrayList sẽ tiết lộ một cấu trúc rất dễ hiểu:

arrayList   ArrayList<String>
  elementData   Object[]
    [0] Object  "Foo"
    [1] Object  "Foo"
    [2] Object  "Foo"
    [3] Object  "Foo"
    [4] Object  "Foo"
    ...

Mặt khác, việc xem nội dung của LinkedList và tìm các đối tượng cụ thể sẽ trở thành cơn ác mộng khi mở rộng Cây, không đề cập đến chi phí nhận thức cần thiết để lọc ra các phần bên trong LinkedList:

linkedList  LinkedList<String>
    header  LinkedList$Entry<E>
        element E
        next    LinkedList$Entry<E>
            element E   "Foo"
            next    LinkedList$Entry<E>
                element E   "Foo"
                next    LinkedList$Entry<E>
                    element E   "Foo"
                    next    LinkedList$Entry<E>
                    previous    LinkedList$Entry<E>
                    ...
                previous    LinkedList$Entry<E>
            previous    LinkedList$Entry<E>
        previous    LinkedList$Entry<E>

17

Trước hết, trong các danh sách liên kết C ++ không nên làm việc nhiều hơn là một mảng. Bạn có thể sử dụng danh sách std :: hoặc danh sách con trỏ boost cho danh sách được liên kết. Các vấn đề chính với danh sách được liên kết so với mảng là không gian thêm cần thiết cho con trỏ và truy cập ngẫu nhiên khủng khiếp. Bạn nên sử dụng một danh sách liên kết nếu bạn

  • bạn không cần truy cập ngẫu nhiên vào dữ liệu
  • bạn sẽ thêm / xóa các phần tử, đặc biệt là ở giữa danh sách

14

Đối với tôi nó là như thế này,

  1. Truy cập

    • Danh sách liên kết chỉ cho phép truy cập tuần tự vào các yếu tố. Do đó, độ phức tạp thuật toán là thứ tự của O (n)
    • Mảng cho phép truy cập ngẫu nhiên vào các phần tử của nó và do đó độ phức tạp là thứ tự của O (1)
  2. Lưu trữ

    • Danh sách liên kết yêu cầu thêm dung lượng để tham khảo. Điều này làm cho chúng không thực tế đối với danh sách các mục dữ liệu nhỏ như ký tự hoặc giá trị boolean.
    • Mảng không cần thêm dung lượng để trỏ đến mục dữ liệu tiếp theo. Mỗi yếu tố có thể được truy cập thông qua các chỉ mục.
  3. Kích thước

    • Kích thước của danh sách Liên kết là tự nhiên.
    • Kích thước của mảng được giới hạn để khai báo.
  4. Chèn / Xóa

    • Các yếu tố có thể được chèn và xóa trong danh sách liên kết vô thời hạn.
    • Chèn / xóa các giá trị trong mảng rất tốn kém. Nó đòi hỏi phải phân bổ lại bộ nhớ.

Bạn có 2 số 2 và 2 số 3 :)
Hengameh

Chúng ta có thể khai báo một mảng trống và sau đó tiếp tục thêm dữ liệu theo yêu cầu. Làm thế nào để nó vẫn còn một kích thước cố định?
HebleV

11

Hai điều:

Mã hóa một danh sách được liên kết, không còn nghi ngờ gì nữa, công việc nhiều hơn một chút so với việc sử dụng một mảng và anh tự hỏi điều gì sẽ biện minh cho nỗ lực bổ sung.

Không bao giờ mã danh sách liên kết khi sử dụng C ++. Chỉ cần sử dụng STL. Việc thực hiện khó đến mức nào không bao giờ là lý do để chọn một cấu trúc dữ liệu khác vì hầu hết đã được triển khai ngoài đó.

Đối với sự khác biệt thực tế giữa một mảng và một danh sách được liên kết, điều quan trọng đối với tôi là cách bạn dự định sử dụng cấu trúc. Tôi sẽ sử dụng vectơ thuật ngữ vì đó là thuật ngữ cho một mảng có thể thay đổi kích thước trong C ++.

Lập chỉ mục vào một danh sách được liên kết là chậm vì bạn phải duyệt qua danh sách để đến chỉ mục đã cho, trong khi một vectơ tiếp giáp trong bộ nhớ và bạn có thể đến đó bằng toán học con trỏ.

Việc thêm vào cuối hoặc đầu danh sách được liên kết rất dễ dàng, vì bạn chỉ phải cập nhật một liên kết, trong đó trong một vectơ bạn có thể phải thay đổi kích thước và sao chép nội dung.

Xóa một mục khỏi danh sách rất dễ dàng, vì bạn chỉ cần ngắt một cặp liên kết và sau đó gắn chúng lại với nhau. Xóa một mục khỏi vectơ có thể nhanh hơn hoặc chậm hơn, tùy thuộc vào việc bạn quan tâm đến thứ tự. Trao đổi trong mục cuối cùng trên đầu mục bạn muốn loại bỏ nhanh hơn, trong khi thay đổi mọi thứ sau khi nó xuống chậm hơn nhưng vẫn giữ trật tự.


Như tôi đã nói với ai đó ở trên, tôi chỉ cố gắng liên hệ câu hỏi theo cách nó được đặt cho tôi. Tôi sẽ không bao giờ sử dụng một mảng (hoặc danh sách liên kết của riêng tôi) trong C ++ - Tôi sẽ sử dụng các phiên bản STL của cả hai.
Onorio Catenacci

10

Eric Lippert gần đây đã có một bài viết về một trong những lý do mảng nên được sử dụng một cách bảo thủ.


2
Phải thừa nhận một bài viết hay, nhưng không liên quan trong danh sách được liên kết so với thảo luận của mảng.
Robert Paulson

2
Tôi đề nghị rằng phần lớn bài viết của Eric có liên quan, vì nó thảo luận về cả nhược điểm của mảng và ưu điểm của Danh sách, bất chấp việc thực hiện danh sách.
Bevan

8

Chèn nhanh và loại bỏ thực sự là đối số tốt nhất cho danh sách được liên kết. Nếu cấu trúc của bạn phát triển linh hoạt và truy cập thời gian liên tục vào bất kỳ yếu tố nào không bắt buộc (chẳng hạn như ngăn xếp và hàng đợi động), danh sách được liên kết là một lựa chọn tốt.


7

Đây là một cách nhanh chóng: Loại bỏ các mục nhanh hơn.


7

Danh sách liên kết đặc biệt hữu ích khi bộ sưu tập liên tục phát triển và thu hẹp. Ví dụ, thật khó để tưởng tượng việc cố gắng thực hiện Hàng đợi (thêm vào cuối, xóa từ phía trước) bằng cách sử dụng một mảng - bạn sẽ dành toàn bộ thời gian để chuyển mọi thứ xuống. Mặt khác, nó tầm thường với một danh sách liên kết.


4
Bạn có thể có một hàng đợi dựa trên mảng mà không cần quá nhiều công việc mà vẫn nhanh / hiệu quả. Bạn chỉ cần theo dõi chỉ số nào là "đầu" và "đuôi". Điều này hoạt động khá tốt nếu bạn cần một hàng đợi có kích thước cố định (ví dụ, bộ đệm bàn phím trong kernel).
Herms

3
Và được gọi là "bộ đệm tròn", nếu bạn muốn tìm kiếm nó trong tài liệu tham khảo thuật toán yêu thích của bạn.
Steve Jessop

7

Khác với việc thêm và xóa từ giữa danh sách, tôi thích các danh sách được liên kết nhiều hơn vì chúng có thể phát triển và thu hẹp một cách linh hoạt.


6
Các vectơ (= về cơ bản là mảng) cũng có thể làm điều đó và chi phí khấu hao cho chúng thường nhỏ hơn so với các danh sách vì các vấn đề liên quan đến địa phương.
Konrad Rudolph

7

Không ai từng mã danh sách liên kết của riêng họ nữa. Điều đó thật ngớ ngẩn. Tiền đề rằng việc sử dụng một danh sách được liên kết sẽ mất nhiều mã hơn là sai.

Ngày nay, việc xây dựng một danh sách liên kết chỉ là một bài tập cho sinh viên để họ có thể hiểu khái niệm này. Thay vào đó, mọi người đều sử dụng một danh sách dựng sẵn. Trong C ++, dựa trên mô tả trong câu hỏi của chúng tôi, điều đó có thể có nghĩa là một vectơ stl ( #include <vector>).

Do đó, việc chọn danh sách được liên kết với một mảng hoàn toàn là cân nhắc các đặc điểm khác nhau của từng cấu trúc so với nhu cầu của ứng dụng của bạn. Vượt qua gánh nặng lập trình bổ sung sẽ không có tác động đến quyết định.


2
Er..umm .. Các std :: vector là một mảng, không phải là một danh sách liên kết. Danh sách liên kết tiêu chuẩn là, tốt, std :: list.
James Curran

1
vâng, nhưng tôi nghĩ rằng vectơ gần hơn với những gì op yêu cầu - một sự thay thế mảng động.
Joel Coehoorn

@Joel, tôi chỉ cố gắng liên hệ câu hỏi vì nó được đặt cho tôi bởi người bạn này đang cố gắng học C ++. Tôi cũng không bận tâm đến việc mã hóa danh sách liên kết của riêng mình nhưng đó là cách anh ấy hỏi tôi. :-)
Onorio Catenacci

Trong các môi trường bị giới hạn bộ nhớ (vi điều khiển) có trình biên dịch tùy chỉnh, không phải tất cả ngôn ngữ (ví dụ: các thùng chứa trong C ++) đều được triển khai. Vì vậy, nó có thể là bạn phải mã danh sách liên kết của riêng bạn. nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus
Minh Trần

6

Đây thực sự là một vấn đề về hiệu quả, chi phí để chèn, loại bỏ hoặc di chuyển (trong đó bạn không chỉ đơn giản là hoán đổi) các phần tử trong danh sách được liên kết là tối thiểu, tức là bản thân thao tác là O (1), câu O (n) cho một mảng. Điều này có thể tạo ra sự khác biệt đáng kể nếu bạn đang hoạt động nhiều trên một danh sách dữ liệu. Bạn đã chọn loại dữ liệu của mình dựa trên cách bạn sẽ vận hành trên chúng và chọn hiệu quả nhất cho thuật toán bạn đang sử dụng.


6

Mảng có ý nghĩa nơi số lượng chính xác của các mục sẽ được biết và nơi tìm kiếm theo chỉ mục có ý nghĩa. Ví dụ: nếu tôi muốn lưu trữ trạng thái chính xác của đầu ra video của mình tại một thời điểm nhất định mà không nén, tôi có thể sử dụng một mảng có kích thước [1024] [768]. Điều này sẽ cung cấp cho tôi chính xác những gì tôi cần, và một danh sách sẽ chậm hơn rất nhiều để có được giá trị của một pixel nhất định. Ở những nơi mà một mảng không có ý nghĩa, thường có các loại dữ liệu tốt hơn một danh sách để xử lý dữ liệu một cách hiệu quả.


6

Mảng Vs Danh sách liên kết:

  1. Cấp phát bộ nhớ mảng đôi khi sẽ thất bại vì bộ nhớ bị phân mảnh.
  2. Bộ nhớ đệm tốt hơn trong Mảng vì tất cả các phần tử được phân bổ không gian bộ nhớ liền kề.
  3. Mã hóa phức tạp hơn Mảng.
  4. Không ràng buộc kích thước trên Danh sách được liên kết, không giống như Mảng
  5. Chèn / Xóa nhanh hơn trong Danh sách được liên kết và truy cập nhanh hơn trong Mảng.
  6. Danh sách liên kết tốt hơn từ quan điểm đa luồng.

-1: Tất cả những điều này cần phải được chứng minh, không chỉ liệt kê.
John Saunders

Mỗi điểm đã được giải thích trong câu trả lời ở trên. Là một người đến sau tôi không có lựa chọn nào khác ngoài việc liệt kê. BTW, cái nào bạn muốn được giải thích?
AKS

Nếu họ đã được giải thích, vậy tại sao bạn trả lời?
John Saunders

2
Vì vậy, nó sẽ cung cấp cho bạn một cái nhìn tóm tắt về các cuộc thảo luận. Và tôi thích những kiểu câu trả lời như vậy để tôi không phải đọc cùng một lời giải thích. Và tôi đã làm điều đó cho những người có cùng suy nghĩ như tôi. Ppl khác nhau có phong cách khác nhau. Không có gì mới.
AKS

3

vì các mảng là tĩnh trong tự nhiên, do đó tất cả các hoạt động như cấp phát bộ nhớ chỉ xảy ra tại thời điểm biên dịch. Vì vậy, bộ xử lý phải đặt ít nỗ lực hơn trong thời gian chạy của nó.


3

Giả sử bạn có một bộ được đặt hàng, bạn cũng muốn sửa đổi bằng cách thêm và xóa các thành phần. Hơn nữa, bạn cần có khả năng giữ lại một tham chiếu đến một phần tử theo cách mà sau này bạn có thể có được một phần tử trước đó hoặc tiếp theo. Ví dụ: danh sách việc cần làm hoặc tập hợp các đoạn văn trong một cuốn sách.

Trước tiên, chúng ta nên lưu ý rằng nếu bạn muốn giữ lại các tham chiếu đến các đối tượng bên ngoài tập hợp, bạn có thể sẽ kết thúc việc lưu trữ các con trỏ trong mảng, thay vì tự lưu trữ các đối tượng. Nếu không, bạn sẽ không thể chèn vào mảng - nếu các đối tượng được nhúng vào mảng, chúng sẽ di chuyển trong quá trình chèn và mọi con trỏ tới chúng sẽ trở nên không hợp lệ. Điều này cũng đúng với các chỉ mục mảng.

Vấn đề đầu tiên của bạn, như bạn đã lưu ý, là chèn - danh sách được liên kết cho phép chèn vào O (1), nhưng một mảng thường sẽ yêu cầu O (n). Vấn đề này có thể được khắc phục một phần - có thể tạo ra một cấu trúc dữ liệu cung cấp giao diện truy cập theo thứ tự giống như mảng trong đó cả đọc và viết, tệ nhất là logarit.

Vấn đề thứ hai và nghiêm trọng hơn của bạn là đưa ra một yếu tố tìm phần tử tiếp theo là O (n). Nếu tập hợp không được sửa đổi, bạn có thể giữ lại chỉ mục của phần tử làm tham chiếu thay vì con trỏ, do đó, tìm kiếm hoạt động O (1) bên cạnh, nhưng đó là tất cả những gì bạn có là một con trỏ đến chính đối tượng và không có cách nào để xác định chỉ mục hiện tại của nó trong mảng khác hơn là quét toàn bộ "mảng". Đây là một vấn đề không thể vượt qua đối với các mảng - ngay cả khi bạn có thể tối ưu hóa các phần chèn thêm, bạn không thể làm gì để tối ưu hóa hoạt động của loại tìm kiếm tiếp theo.


Bạn có thể vui lòng giải thích điều này: "có thể tạo ra một cấu trúc dữ liệu cung cấp giao diện truy cập theo thứ tự giống như mảng trong đó cả đọc và viết, tệ nhất là logarit."
Hengameh

1
Có một số nội dung trên Wikipedia trong phần Dynamic Array / Vriants. Nó không hoàn toàn như tôi nghĩ, mặc dù ... Hãy tưởng tượng một cấu trúc giống như cây b + với các trang nhưng không có khóa, thay vào đó mỗi trang trung gian ghi nhớ có bao nhiêu phần tử trong mỗi trang phụ, trong khi các trang lá chỉ giữ các phần tử trong một mảng nhỏ. Khi chèn một phần tử vào trang lá, bạn phải di chuyển ~ một nửa trang để tạo khoảng trống, sau đó đi lên và cập nhật số mục trên tất cả các trang của tổ tiên. Khi tìm kiếm một phần tử #N, chỉ cần thêm số mục trang phụ cho đến khi bạn vượt qua N, và sau đó đi xuống cây con đó
DenNukem

3

Trong một mảng, bạn có đặc quyền truy cập bất kỳ phần tử nào trong thời gian O (1). Vì vậy, nó phù hợp cho các hoạt động như Tìm kiếm nhị phân Sắp xếp nhanh, v.v. Mặt khác, danh sách được liên kết phù hợp để xóa chèn như trong thời gian O (1). Cả hai đều có những ưu điểm cũng như nhược điểm và thích cái này hơn cái khác để hiểu rõ hơn những gì bạn muốn thực hiện.

- Câu hỏi lớn hơn là chúng ta có thể có một kết hợp của cả hai. Một cái gì đó giống như những gì python và perl thực hiện như danh sách.


3

Danh sách liên kết

Nó thích hợp hơn khi nói về chèn! Về cơ bản những gì nó làm là nó liên quan đến con trỏ

1 -> 3 -> 4

Chèn (2)

1 ........ 3 ...... 4
..... 2

Cuối cùng

1 -> 2 -> 3 -> 4

Một mũi tên từ 2 điểm tại 3 và mũi tên 1 điểm tại 2

Đơn giản!

Nhưng từ Mảng

| 1 | 3 | 4 |

Chèn (2) | 1 | 3 | | 4 | | 1 | | 3 | 4 | | 1 | 2 | 3 | 4 |

Vâng bất cứ ai cũng có thể hình dung sự khác biệt! Chỉ với 4 chỉ số, chúng tôi đang thực hiện 3 bước

Nếu chiều dài mảng là một triệu thì sao? Là mảng hiệu quả? Câu trả lời là không! :)

Điều tương tự cũng xảy ra với việc xóa! Trong Danh sách liên kết, chúng ta chỉ cần sử dụng con trỏ và vô hiệu hóa phần tử và tiếp theo trong lớp đối tượng! Nhưng đối với mảng, chúng ta cần thực hiện shiftLeft ()

Mong rằng sẽ giúp! :)


3

Danh sách liên kết có nhiều chi phí để duy trì hơn mảng, nó cũng yêu cầu lưu trữ bộ nhớ bổ sung, tất cả các điểm này đều được thỏa thuận. Nhưng có một vài điều mà mảng không thể làm. Trong nhiều trường hợp, giả sử bạn muốn có một mảng có độ dài 10 ^ 9, bạn không thể có được nó vì phải có một vị trí bộ nhớ liên tục phải ở đó. Danh sách liên kết có thể là một vị cứu tinh ở đây.

Giả sử bạn muốn lưu trữ nhiều thứ với dữ liệu thì chúng có thể dễ dàng được mở rộng trong danh sách được liên kết.

Các container STL thường có danh sách liên kết thực hiện phía sau hiện trường.


3

1- Danh sách liên kết là một cấu trúc dữ liệu động để nó có thể phát triển và thu hẹp khi chạy bằng cách phân bổ và giải phóng bộ nhớ. Vì vậy, không cần phải đưa ra một kích thước ban đầu của danh sách được liên kết. Chèn và xóa các nút thực sự dễ dàng hơn.

2- kích thước của danh sách được liên kết có thể tăng hoặc giảm trong thời gian chạy để không lãng phí bộ nhớ. Trong trường hợp của mảng, có rất nhiều sự lãng phí bộ nhớ, như nếu chúng ta khai báo một mảng có kích thước 10 và chỉ lưu trữ 6 phần tử trong đó thì không gian của 4 phần tử bị lãng phí. Không có vấn đề như vậy trong danh sách được liên kết vì bộ nhớ chỉ được phân bổ khi được yêu cầu.

3- Các cấu trúc dữ liệu như ngăn xếp và hàng đợi có thể được thực hiện dễ dàng bằng cách sử dụng danh sách được liên kết.


2

Lý do duy nhất để sử dụng danh sách được liên kết là việc chèn phần tử là dễ dàng (cũng loại bỏ).

Disadvatige có thể là con trỏ chiếm rất nhiều không gian.

Và về việc mã hóa thì khó hơn: Thông thường bạn không cần danh sách liên kết mã (hoặc chỉ một lần) chúng được đưa vào STL và nó không quá phức tạp nếu bạn vẫn phải làm điều đó.


2
Con trỏ mất rất nhiều không gian? Không hẳn vậy. Nếu bạn đang lưu trữ một danh sách booleans được liên kết, thì chắc chắn, phần trăm thông minh con trỏ chiếm rất nhiều không gian. Nhưng nếu bạn đang lưu trữ các đối tượng phức tạp (thường là trường hợp này) thì con trỏ có thể không đáng kể.
Herms

quên nụ cười :) Nhưng đã nói 'không thể' là 'là'.
dùng15453

1

tôi cũng nghĩ rằng danh sách liên kết là tốt hơn so với mảng. bởi vì chúng tôi duyệt qua danh sách liên kết nhưng không phải trong mảng


1

Tùy thuộc vào ngôn ngữ của bạn, một số nhược điểm và ưu điểm có thể được xem xét:

Ngôn ngữ lập trình C : Khi sử dụng danh sách được liên kết (thông qua các con trỏ cấu trúc), phải xem xét đặc biệt rằng bạn không bị rò rỉ bộ nhớ. Như đã đề cập trước đó, các danh sách được liên kết rất dễ xáo trộn, bởi vì tất cả những gì đang làm là thay đổi con trỏ, nhưng chúng ta sẽ nhớ để giải phóng mọi thứ chứ?

Java : Java có tính năng thu gom rác tự động, do đó bộ nhớ bị rò rỉ sẽ không phải là vấn đề, nhưng ẩn với lập trình viên cấp cao là chi tiết triển khai của danh sách được liên kết là gì. Các phương thức như loại bỏ một nút khỏi giữa danh sách là một thủ tục phức tạp hơn so với một số người dùng ngôn ngữ sẽ mong đợi nó.


1

Tại sao một danh sách liên kết trên một mảng? Như một số người đã nói, tốc độ chèn và xóa lớn hơn.

Nhưng có lẽ chúng ta không phải sống với giới hạn của một trong hai, và có được thứ tốt nhất của cả hai, cùng một lúc ... eh?

Đối với việc xóa mảng, bạn có thể sử dụng byte 'Đã xóa', để thể hiện thực tế là một hàng đã bị xóa, do đó, việc sắp xếp lại mảng không còn cần thiết nữa. Để giảm bớt gánh nặng của việc chèn thêm hoặc thay đổi dữ liệu nhanh chóng, hãy sử dụng danh sách được liên kết cho điều đó. Sau đó, khi đề cập đến chúng, có logic của bạn đầu tiên tìm kiếm một, sau đó khác. Do đó, sử dụng chúng kết hợp mang lại cho bạn tốt nhất của cả hai.

Nếu bạn có một mảng thực sự lớn, bạn có thể kết hợp nó với một mảng khác, nhỏ hơn nhiều hoặc danh sách được liên kết trong đó một mảng nhỏ hơn chứa 20, 50, 100 mục được sử dụng gần đây nhất. Nếu cái cần thiết không nằm trong danh sách hoặc mảng được liên kết ngắn hơn, bạn chuyển đến mảng lớn. Nếu được tìm thấy ở đó, sau đó bạn có thể thêm nó vào danh sách / mảng được liên kết nhỏ hơn với giả định rằng 'những thứ được sử dụng gần đây nhất sẽ được sử dụng lại' (và có, có thể làm hỏng mục được sử dụng gần đây nhất từ ​​danh sách). Điều này đúng trong nhiều trường hợp và đã giải quyết được một vấn đề mà tôi phải giải quyết trong một mô-đun kiểm tra quyền bảo mật .ASP, với sự dễ dàng, thanh lịch và tốc độ ấn tượng.


1

Trong khi nhiều bạn đã chạm vào các ưu điểm chính của danh sách được liên kết và mảng, hầu hết các so sánh là cách một cái tốt hơn / kém hơn cái kia.Eg. bạn có thể truy cập ngẫu nhiên trong mảng nhưng không thể trong danh sách được liên kết và những thứ khác. Tuy nhiên, đây là giả định danh sách liên kết và mảng sẽ được áp dụng trong một ứng dụng tương tự. Tuy nhiên, một câu trả lời đúng phải là cách danh sách liên kết sẽ được ưu tiên hơn mảng và ngược lại trong một triển khai ứng dụng cụ thể. Giả sử bạn muốn thực hiện một ứng dụng từ điển, bạn sẽ sử dụng cái gì? Mảng: mmm nó sẽ cho phép dễ dàng truy xuất thông qua tìm kiếm nhị phân và tìm kiếm khác .. nhưng hãy nghĩ làm thế nào danh sách liên kết có thể tốt hơn..Say bạn muốn tìm kiếm "Blob" trong từ điển. Sẽ có ý nghĩa khi có một danh sách liên kết của A-> B-> C-> D ---->

A -> B -> C -> ...Z
|    |    |
|    |    [Cat, Cave]
|    [Banana, Blob]
[Adam, Apple]

Bây giờ là cách tiếp cận trên tốt hơn hay là một mảng phẳng của [Adam, Apple, Banana, Blob, Cat, Cave]? Nó thậm chí sẽ có thể với mảng? Vì vậy, một lợi thế lớn của danh sách liên kết là bạn có thể có một phần tử không chỉ trỏ đến phần tử tiếp theo mà còn đến một số danh sách liên kết / mảng / heap / hoặc bất kỳ vị trí bộ nhớ nào khác. Mảng là một bộ nhớ liền kề phẳng được cắt thành kích thước khối của phần tử mà nó sẽ lưu trữ .. Mặt khác, danh sách liên kết là một khối các đơn vị bộ nhớ không liền kề (có thể là bất kỳ kích thước nào và có thể lưu trữ mọi thứ) và chỉ vào từng phần khác theo cách bạn muốn. Tương tự như vậy, hãy nói rằng bạn đang tạo một ổ đĩa USB. Bây giờ bạn có muốn các tệp được lưu dưới dạng bất kỳ mảng hoặc dưới dạng danh sách liên kết không? Tôi nghĩ rằng bạn có ý tưởng về những gì tôi đang chỉ vào :)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.