2013-05-08 39 views
8

Tôi đang học sys/queue.h từ FreeBSD và tôi có một câu hỏi:Tại sao danh sách được liên kết kép trong sys/queue.h duy trì địa chỉ của phần tử tiếp theo trước đó?

Trong sys/queue.h, LIST_ENTRY được định nghĩa như sau:

#define LIST_ENTRY(type)      \ 
struct {        \ 
    struct type *le_next; /* next element */   \ 
    struct type **le_prev; /* address of previous next element */ \ 
} 

Tại sao nó duy trì địa chỉ của phần tử tiếp theo trước (struct type **le_prev) thay vì chỉ đơn giản là elment trước như struct type *le_prev?

Trả lời

8

Nếu bạn đã có thể đọc các tập tin queue.h từ đầu, bạn có thể đã có lời nhận xét sau đây:

* A list is headed by a single forward pointer (or an array of forward 
* pointers for a hash table header). The elements are doubly linked 
* so that an arbitrary element can be removed without a need to 
* traverse the list. New elements can be added to the list before 
* or after an existing element or at the head of the list. A list 
* may only be traversed in the forward direction. 

nên danh sách, trong đó cung cấp O (1) chèn và xóa, nhưng chỉ về phía trước traversal. Để đạt được điều này, bạn chỉ cần tham chiếu đến con trỏ tiếp theo trước đó, chính xác là những gì được thực hiện .

+0

Bạn có nghĩa là việc triển khai này nhằm ngăn chặn việc truyền tải ngược cũng như đạt được O (1) chèn và xóa không? –

+0

@YanzheChen phức tạp của (tuyến tính) danh sách hoạt động sẽ không thay đổi khi bạn sử dụng một con trỏ duy nhất và và con trỏ đôi không ngăn chặn traversal lạc hậu. Tôi nghĩ, phần quan trọng là "hoặc một mảng con trỏ tiến"; khi có bảng (băm) như vậy, việc loại bỏ sẽ rẻ hơn khi địa chỉ của con trỏ trước đó được lưu trữ. – ensc

+0

@ensc Tôi đã đọc [bài đăng] này (http://stackoverflow.com/questions/9362896/deleting-any-node-from-a-single-linked-list-when-only-pointer-to-that-node- is-gi) và hiểu rằng việc xóa trong danh sách liên kết đơn có thể đạt được trong O (1) nếu nó không phải là nút đuôi. Nhưng tại sao con trỏ kép không ** không ** ngăn chặn sự truyền tải ngược? Làm thế nào để thực hiện các traversal lạc hậu? Và tôi không hiểu ** phần quan trọng ** bạn đã đề cập đến. Bạn có thể giải thích điều này chi tiết hơn không? –

0

Hãy để tôi cố giải thích. Trên thực tế, **le_prev* dành ablity vào danh sách được xác định bởi sys/queue.h để insert_before mà chuyển tiếp danh sách có thể không. So với insert_before, insert_after có thể được triển khai tốt trong danh sách hoặc danh sách chuyển tiếp. Vì vậy, danh sách là chức năng hơn.

insert_before(entry* list_elem, entry* elem, type val) 
{ 
    elem->next = list_elem; 
    *(list->prev) = elem; 
    elem->prev = *(list->prev); 
    list_elem->prev = elem->next; 
} 
insert_after(entry* list_elem, entry* elem, type val) 
{ 
    if(((elem)->next= (list_elem)->next) != NULL) { 
     (elem_list)->next->prev = &(elem)->next; 
    } 
    (list_elem)->next = elem; 
    elem->prev = &(list_elem)->next; 
}