Các thao tác trên danh sách móc nối

Một phần của tài liệu Giáo trình Kỹ thuật lập trình (Trang 64)

Các thao tác trên danh sách móc nối bao gồm việc cấp phát bộ nhớ cho các đỉnh và gán dữ liệu cho con trỏ. Để danh sách được tạo nên đúng đắn, ta biểu diễn phần tử cuối danh sách là một con trỏ NULL. Con trỏ NULL là tín hiệu thông báo không còn phần tử

nào tiếp theo trong danh sách nữa.

Tiện hơn cả là chúng ta định nghĩa một con trỏ tới danh sách như sau:

struct node { int infor; struct node *next; };

typedef struct node *NODEPTR; // Con trỏ tới node

Cấp phát bộ nhớ cho một node:

NODEPTR Getnode(void) { NODEPTR p;

P = (NODEPTR) malloc(sizeof( struct node)); Return(p);

}

Giải phóng bộ nhớ của một node”

NODEPTR Freenode( NODEPTR p){ free(p);

}

Chèn một phần tử mới vào đầu danh sách:

Các bước để chèn một phần tử mới vào đầu danh sách cần thực hiện là:

9 Cấp không gian bộ nhớđủ lưu giữ một đỉnh mới;

9 Thiết lập liên kết với đỉnh mới.

Sơđồ biểu diễn phép thêm một đỉnh mới vào đầu danh sách được thể hiện như trên hình 3.5.

Node cần chèn vào đầu danh sách móc nối.

Hình 3.5. Thêm đỉnh mới vào đầu danh sách móc nối đơn

void Push_Top( NODEPTR *plist, int x) { NODEPTR p;

p= Getnode(); // cấp không gian nhớ cho đỉnh mới p -> infor = x; // gán giá trị thích hợp cho đỉnh mới p ->next = *plist;

*plist = p; // thiết lập liên kết }

Thêm một phần tử mới vào cuối danh sách:

Để thêm một node vào cuối danh sách, ta cần thực hiện qua các bước sau:

9 Cấp phát bộ nhớ cho node mới;

9 Gán giá trị thích hợp cho node mới;

9 Di chuyển con trỏ tới phần tử cuối danh sách;

9 Thiết lập liên kết cho node mới.

Sơ đồ thể hiên phép thêm một phần tử mới vào cuối danh sách được thể hiện như

trong hình 3.6

infor next infor next infor next

infor next

infor next infor next infor next

void Push_Bottom( NODEPTR *plist, int x) { NODEPTR p, q;

p= Getnode(); // cấp phát bộ nhớ cho node mới p->infor = x; // gán giá trị thông tin thích hợp q = *plist; // chuyển con trỏ tới cuối danh sách while (q-> next != NULL)

q = q -> next;

// q là node cuối cùng của danh sách liên kết q -> next = p; //node cuối bây giờ là node p; p ->next = NULL; // liên kết mới của p }

Thêm node mới q vào giữa danh sách trước node p:

Để thêm node q vào trước node p, chúng ta cần lưu ý node p phải có thực trong danh sách. Giả sử node p là có thực, khi đó xảy ra hai tình huống: hoặc node p là node cuối cùng của danh sách liên kết tức p->next =NULL, hoặc node p chưa phải là cuối cùng hay p->next != NULL. Trường hợp thứ nhất, chúng ta chỉ cần gọi tới thao tác Push_Bottom(). Trường hợp thứ 2, chúng ta thực hiện theo các bước như sau:

9 Cấp phát bộ nhớ cho node mới;

9 Gán giá trị thích hợp cho node;

9 Thiết lập liên kết node q với node kế tiếp p;

9 Thiết lập liên kết node node p với node q;

void Push_Before( NODEPTR p, int x ){ NODEPTR q;

if (p->next==NULL) Push_Bottom(p, x);

else {

q= Getnode(); // cấp phát bộ nhớ cho node mới q -> infor = x; // gán giá trị thông tin thích hợp

q-> next = p-> next; // thiết lập liên kết node q với node kế tiếp p; p->next = q; // thiết lập liên kết node p với node kế tiếp q; }

}

p

q

Hình 3.7. Phép thêm phần tử vào giữa danh sách liên kết đơn.

Xoá một node ra khỏi đầu danh sách:

Khi loại bỏ node khỏi đầu danh sách liên kết, chúng ta cần chú ý rằng nếu danh sách đang rỗng thì không thể thực hiện việc loại bỏ. Trong trường hợp còn lại, ta thực hiện như sau:

9 Dùng node p trỏ tới đầu danh sách;

9 Dịch chuyển vị trí đầu danh sách tới node tiếp theo;

9 Loại bỏ liên kết với p;

9 Giải phóng node p;

void Del_Top( NODEPTR *plist) { NODEPTR p;

p = *plist; // node p trỏ tới đầu danh sách; if (p==NULL) return; // danh sách rỗng

(*plist) = (*plist) -> next; // dịch chuyển node gốc lên node kế tiếp p-> next = NULL; //loại bỏ liên kết với p

Freenode(p); // giải phóng p; }

Loại bỏ node ở cuối danh sách:

Một node ở cuối danh sách có thể xảy ra ba tình huống sau:

9 Danh sách rỗng: ta không cần thực hiện loại bỏ;

9 Danh sách chỉ có đúng một node: ứng với trường hợp loại bỏ node gốc; Trường hợp còn lại danh sách có nhiều hơn một node, khi đó ta phải dịch chuyển tới node gần node cuối cùng nhất để thực hiện loại bỏ.

void Del_Bottom(NODEPTR *plist) { NODEPTR p, q;

if (*plist==NULL) return; //không làm gì

else if ( (*plist)->next==NULL)) // danh sách có một node Del_Top(plist);

infor next

infor next infor next infor next

p = *plist;

while (p->next!=NULL){

q = p;

p = p->next; // q là node sau node p;

}

// p là node cuối danh sách;

q->next =NULL; //node cuối cùng là q Freenode(p); //giải phóng p;

} }

Loại bỏ node ở giữa danh sách (trước node p):

Cần để ý rằng, nếu trước node pNULL (p->next==NULL) thì ta không thực hiện loại bỏđược. Trường hợp còn lại chúng ta thực hiện như sau:

9 Dùng node q trỏ tới node trước node p;

9 Loại bỏ liên kết của q;

9 Giải phóng q.

void Del_before(NODEPTR p){ NODEPTR q;

if (p->next==NULL) return; // không làm gì q = p ->next;

p->next = q->next; Freenode(q); }

Bạn đọc có thể tìm thấy những cài đặt cụ thể của danh sách liên kết đơn trong các tài liệu [1], [2].

Một phần của tài liệu Giáo trình Kỹ thuật lập trình (Trang 64)

Tải bản đầy đủ (PDF)

(156 trang)