Tôi hiếm khi sử dụng một con trỏ đuôi cho các danh sách được liên kết và có xu hướng sử dụng các danh sách liên kết đơn thường xuyên hơn trong đó một kiểu chèn / pop giống như ngăn xếp và loại bỏ (hoặc chỉ loại bỏ thời gian tuyến tính từ giữa). Đó là bởi vì trong các trường hợp sử dụng thông thường của tôi, con trỏ đuôi thực sự đắt tiền, giống như làm cho danh sách liên kết đơn thành một danh sách liên kết đôi là đắt tiền.
Thông thường việc sử dụng trường hợp phổ biến của tôi cho danh sách liên kết đơn có thể lưu trữ hàng trăm ngàn danh sách được liên kết chỉ chứa một vài nút danh sách. Tôi cũng thường không sử dụng con trỏ cho danh sách liên kết. Tôi sử dụng các chỉ mục vào một mảng thay vì các chỉ mục có thể là 32 bit, ví dụ, chiếm một nửa không gian của con trỏ 64 bit. Tôi cũng thường không phân bổ các nút danh sách một lần và thay vào đó, chỉ sử dụng một mảng lớn để lưu trữ tất cả các nút và sau đó sử dụng các chỉ mục 32 bit để liên kết các nút lại với nhau.
Ví dụ, hãy tưởng tượng một trò chơi video sử dụng lưới 400x400 để phân vùng một triệu hạt di chuyển xung quanh và bật ra khỏi nhau để tăng tốc phát hiện va chạm. Trong trường hợp đó, một cách khá hiệu quả để lưu trữ đó là lưu trữ 160.000 danh sách liên kết đơn, chuyển thành 160.000 số nguyên 32 bit trong trường hợp của tôi (~ 640 kilobyte) và một chi phí nguyên 32 bit cho mỗi hạt. Bây giờ khi các hạt di chuyển xung quanh trên màn hình, tất cả những gì chúng ta phải làm là cập nhật một vài số nguyên 32 bit để di chuyển một hạt từ ô này sang ô khác, như vậy:
... với next
chỉ mục ("con trỏ") của nút hạt đóng vai trò là chỉ mục cho hạt tiếp theo trong ô hoặc hạt tự do tiếp theo để lấy lại nếu hạt đã chết (về cơ bản là thực thi cấp phát danh sách miễn phí bằng chỉ số):
Việc loại bỏ thời gian tuyến tính khỏi một ô không thực sự là một chi phí vì chúng ta đang xử lý logic hạt bằng cách lặp qua các hạt trong một ô, do đó, một danh sách liên kết đôi sẽ chỉ thêm chi phí không có ích tất cả trong trường hợp của tôi cũng giống như một cái đuôi sẽ không có lợi cho tôi cả.
Một con trỏ đuôi sẽ tăng gấp đôi mức sử dụng bộ nhớ của lưới cũng như tăng số lần bỏ lỡ bộ đệm. Nó cũng yêu cầu chèn để yêu cầu một nhánh để kiểm tra xem danh sách có trống không thay vì không có nhánh. Làm cho nó trở thành một danh sách liên kết đôi sẽ tăng gấp đôi chi phí danh sách của mỗi hạt. 90% thời gian tôi sử dụng các danh sách được liên kết, đó là cho các trường hợp như thế này, và do đó, một con trỏ đuôi thực sự sẽ tương đối tốn kém để lưu trữ.
Vì vậy, 4-8 byte thực sự không tầm thường trong hầu hết các bối cảnh mà tôi sử dụng danh sách được liên kết ở vị trí đầu tiên. Chỉ muốn gắn chip vào đó vì nếu bạn đang sử dụng cấu trúc dữ liệu để lưu trữ một khối lượng phần tử, thì 4-8 byte có thể không phải lúc nào cũng không đáng kể. Tôi thực sự sử dụng các danh sách được liên kết để giảm phân bổ số lượng bộ nhớ và số lượng bộ nhớ cần thiết, ngược lại, lưu trữ 160.000 mảng động phát triển cho lưới có sử dụng bộ nhớ nổ (thường là một con trỏ cộng với ít nhất hai số nguyên cho mỗi ô lưới cùng với phân bổ heap cho mỗi ô lưới trái ngược với chỉ một phân bổ heap và số nguyên cho mỗi ô).
Tôi thường thấy nhiều người tiếp cận với các danh sách được liên kết vì độ phức tạp liên tục của họ liên quan đến việc loại bỏ trước / giữa và chèn trước / giữa khi LL thường là một lựa chọn kém trong những trường hợp do thiếu liên tục chung. Trong đó các LL rất đẹp đối với tôi từ quan điểm hiệu năng là khả năng chỉ cần di chuyển một yếu tố từ danh sách này sang danh sách khác bằng cách thao tác một vài con trỏ và có thể đạt được cấu trúc dữ liệu có kích thước thay đổi mà không cần bộ cấp phát bộ nhớ có kích thước thay đổi (kể từ đó mỗi nút có kích thước đồng nhất, chúng ta có thể sử dụng danh sách miễn phí, vd). Nếu mỗi nút danh sách đang được phân bổ riêng cho phân bổ mục đích chung, thì thông thường khi danh sách được liên kết sẽ bị giảm giá trị so với các lựa chọn thay thế và đó là '
Thay vào đó, tôi đề nghị rằng trong hầu hết các trường hợp danh sách được liên kết đóng vai trò tối ưu hóa rất hiệu quả so với các lựa chọn đơn giản, các hình thức hữu ích nhất thường được liên kết đơn lẻ, chỉ cần một con trỏ đầu và không yêu cầu cấp phát bộ nhớ cho mục đích chung nút và thay vào đó thường có thể chỉ là bộ nhớ nhóm đã được phân bổ cho mỗi nút (từ một mảng lớn đã được phân bổ trước, ví dụ). Ngoài ra, mỗi SLL thường sẽ lưu trữ một số lượng rất nhỏ các phần tử trong các trường hợp đó, như các cạnh được kết nối với một nút biểu đồ (nhiều danh sách được liên kết nhỏ so với một danh sách được liên kết lớn).
Cũng đáng lưu ý rằng chúng ta có một khối lượng DRAM ngày nay nhưng đó là loại bộ nhớ chậm thứ hai có sẵn. Chúng tôi vẫn ở mức 64 KB mỗi lõi khi nói đến bộ đệm L1 với các dòng bộ đệm 64 byte. Kết quả là, những khoản tiết kiệm byte nhỏ đó thực sự có thể quan trọng trong một khu vực quan trọng về hiệu năng như sim hạt ở trên khi được nhân lên hàng triệu lần nếu điều đó có nghĩa là sự khác biệt giữa việc lưu trữ gấp đôi số nút vào một dòng bộ đệm hay không, ví dụ