Ấu trúc dữ liệu + Thuật tốn =h ươngtrình

Một phần của tài liệu Giáo trình cấu trúc dữ liệu và giải thuật (Trang 83 - 88)

III.4.2. DSLK vịng

DSLK vịng là DSLK mà nút cuối là nút kề trước của nút đầu.

Nếu cài đặt DSLK vịng bằng kiểu con trỏ thì con trỏ của nút cuối trỏ đến nút đầu tiên. Trong DSLK vịng, ta cĩ thể lấy bất cứ nút nào làm nút đầu tiên xuất phát. Cấu trúc dữ liệu cho mỗi nút của DSLK vịng hồn tồn giống như DSLK

đơn.

CList.Head CList.Tail

Một số thao tác cơ bản cho DSLK vịng sẽđược viết lại sau đây, các thao tác khác được xem như bài tập.

Khi to mt DSLK vịng rng

LL CreateEmptyCLL ()

{ LL CList;

CList.Head = CList.Tail = NULL; return List;

}

Kim tra mt DSLK vịng cĩ rng hay khơng

int EmptyCLL(LL CList)

{

return(CList.Head == NULL && CList.Tail == NULL);

}

Duyt qua mt DSLK vịng

int TraverseCLL(LL CList)

{ NodePointer CurrPtr = CList.Head if (EmptyCLL(CList)) return 0; do

{ XửLý (CurrPtr);

CurrPtr = CurrPtr->Next;

} while (CurrPtr->Next != Clist.Head); return 1;

}

III.4.3. DSLK đối xứng

Trong nhiều thao tác trên kiểu DSLK đơn, khi làm việc với một nút ta cần biết nút đứng kề trước của nĩ. Lý do là DSLK đơn chỉ cĩ một liên kết đi theo một chiều từ nút đứng trước đến nút đứng sau. Để tăng độ linh hoạt trong các thao tác trên DSLK, cĩ thể di chuyển từ đầu đến đuơi của danh sách hay ngược lại, ta xét kiểu DSLK đối xứng (hay DSLK kép) mà mỗi nút cĩ hai trường liên kết ngược chiều nhau, một liên kết chỉ đến nút đứng sau và liên kết kia chỉ đến nút đứng trước.

DList.Head Prev Data Next DList.Tail

• •

a. Cu trúc d liu biu din DSLK đối xng

Trong C hay C++, mỗi nút của DSLK đối xứng được cài đặt bởi cấu trúc sau:

typedef .... ElementType; // Kiểu dữ liệu cơ sở của mỗi phần tử

struct Dnode *Next, *Prev; } DNodeType;

typedef DNodeType *DNodePointer; typedef struct { DNodePointer Head, Tail;

} DLL; DLL DList;

b. Các thao tác cơ bn trên DSLK đối xng

Các thao tác cơ bản về sau sẽ sử dụng thủ tục cấp phát động vùng nhớ cho một nút của DSLK đối xứng sau đây: • Cp phát vùng nh cha d liu x cho mt nút ca DSLK đối xng Head • x • Tail - Thut tốn DNodePointer CreateNodeDLL (x) . Cấp phát vùng nhớ cho một nút new_ele;

. new_ele ->Data = x; new_ele ->Next = NULL; new_ele ->Prev = NULL; . Trả về new_ele; . Trả về new_ele;

- Cài đặt

DNodePointer CreateNodeDLL (ElementType x)

{ DNodePointer new_ele;

if ((new_ele = new DNodeType) ==NULL)

cout << “\nLỗi cấp phát vùng nhớ cho một nút mới !”; else { Gán(new_ele ->Data, x);

new_ele ->Next = new_ele ->Prev = NULL;

}return new_ele; return new_ele; } • Khi to mt DSLK đối xng rng. - Thut tốn DLL CreateEmptyDLL ()

. DList.Head = DList.Tail = NULL; . Trả về DList;

- Cài đặt

DLL CreateEmptyDLL ()

{ DLL List;

DList.Head = DList.Tail = NULL;

}

Kim tra mt DSLK đối xng cĩ rng hay khơng

- Thut tốn

Boolean EmptyDLL(DLL DList)

if (DList.Head == NULL)

// hay (DList.Head == NULL) && (DList.Tail == NULL). Tại sao ? Hãy so sánh !

Trả trị True; // DList rỗng; else Trả trị False; // DList khác rỗng;

- Cài đặt

int EmptyDLL(DLL DList)

{ return(DList.Head == NULL);

// hay return ((DList.Head == NULL) && (DList.Tail == NULL));

}

Duyt qua mt DSLK đối xng

Ta cĩ thể duyệt Dlist theo chiều thuận (hay ngược) tùy theo chiều con trỏ

Next (hay Prev).

- Thut tốn TraverseLL(DList)

. CurrPtr = DList.Head; // hay CurrPtr = DList.Tail; . Trong khi chưa hết DSLK thực hiện:

{ XửLý nút được trỏ bởi CurrPtr;

CurrPtr = CurrPtr->Next; // chuyển đến nút kề sau // hay CurrPtr = CurrPtr->Prev; chuyển đến nút kề trước }

- Cài đặt

int TraverseDLL(DLL DList)

{ DNodePointer CurrPtr = DList.Head; // hay CurrPtr = DList.Tail; if (EmptyDLL(DList)) return 0;

else { while (CurrPtr != NULL) // hoặc while (CurrPtr) { XửLý (CurrPtr);

CurrPtr = CurrPtr->Next; // hay CurrPtr = CurrPtr->Prev;

}

return 1;

} }

void X(DNodePointer CurrPtr)

{ // Xử lý nút CurrPtr tùy theo từng yêu cầu cụ thể

return ;

}

Thêm mt phn t mi vào DSLK đối xng

* Thêm một phần tử vào sau một nút được trỏ bởi con trỏ PredPtr

(nếu PredPtr == NULL thì chèn phn t vào đầu DSLK)

DList.Head Prev Data Next DList.Tail

• •

3 2 1 4

PredPtr X

new_ele

- Thut tốn: Thêm một nút new_ele vào sau một nút được trỏ bởi PredPtr

InsertNodeAfterDLL(&DList, new_ele, PredPtr)

. if (PredPtr)

{ new_ele->Next = PredPtr->Next; new_ele->Prev = PredPtr; PredPtr->Next = new_ele;

if (new_ele->Next) (new_ele->Next)->Prev = new_ele;

// else: trường hợp chèn new_ele vào đuơi DList, khơng cập nhật nút sau nút new_ele }

else // chèn new_ele vào đầu Dlist

{ new_ele->Next = DList.Head;

if (DList.Head) DList.Head->Prev = new_ele; // else DS rỗng !

DList.Head = new_ele; //cập nhật lại nút đầu DS }

// nếu chèn nút mới vào đuơi, cần cập nhật lại đuơi mới . if (PredPtr == DList.Tail) DList.Tail = new_ele;

- Cài đặt

void InsertNodeAfterDLL(DLL &DList, DNodePointer new_ele,DNodePointer PredPtr)

{ if (PredPtr)

{ new_ele->Next = PredPtr->next; new_ele->Prev = PredPtr; PredPtr->Next = new_ele;

if (new_ele->Next) (new_ele->Next)->Prev = new_ele; }

else { new_ele->Next = DList.Head;

if (DList.Head) DList.Head->Prev = new_ele; DList.Head = new_ele;

}

if (PredPtr == DList.Tail) DList.Tail = new_ele; return ;

Thut tốn: Thêm phần tử x vào sau một nút được trỏ bởi con trỏ PredPtr

DNodePointer InsertElementAfterDLL (&DList, x, PredPtr) . new_ele = CreateNodeDLL (x);

. if (new_ele ≠ NULL) Thêm nút new_ele vào sau nút được trỏ bởi PredPtr;

. Trả về trị new_ele;

- Cài đặt

DNodePointer InsertElementAfterDLL(DLL &DList,ElementType x,DNodePointer PredPtr)

{ DNodePointer new_ele;

if ((new_ele = CreateNodeDLL (x)))

InsertNodeAfterDLL (DList, new_ele, PredPtr); return (new_ele);

}

Tương tự, ta cĩ thao tác thêm một nút (hay phần tử) vào trước một nút được trỏ bởi con trỏSuccPtr (bài tập).

Thêm một phần tử vào cuối một DSLK đối xứng

Một phần của tài liệu Giáo trình cấu trúc dữ liệu và giải thuật (Trang 83 - 88)

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

(148 trang)