You are on page 1of 14

3.2.3.

Danh sách liên kết kép


Danh sách liên kết kép là danh sách mà mỗi phần tử trong danh sách liên kết với các phần tử
đứng trước và sau nó bằng hai mối liên kết.

3.2.3.1. Định nghĩa cấu trúc dữ liệu của một nút


Cấu trúc dữ liệu một nút
typedef struct tagDnode
{ Data Info;
struct tagDnode *pPre;
struct tagDnode *pNext;
} DNode;
Cấu trúc danh sách kép
typedef struct tagDList
{ DNode *pHead;
DNode *pTail;
}DList;

3.2.3.2. Các thao tác trên danh sách liên kép


• Khởi tạo danh sách liên kết kép rỗng
• Tạo một nút có thành phần dữ liệu là x
• Chèn một phần tử vào danh sách
 Chèn phần tử vào đầu danh sách
 Chèn phần tử vào cuối danh sách
 Chèn phần tử vào sau phần tử q cho trước trong danh sách
 Chèn phần tử vào trước phần tử q cho trước trong danh sách
• Huỷ một phần tử trong danh sách
 Hủy phần tử đầu danh sách
 Hủy phần tử cuối danh sách
 Hủy một phần tử có khoá bằng x
 Hủy phần tử sau phần tử q cho trước trong danh sách
 Hủy phần tử trước phần tử q cho trước trong danh sách
• Duyệt danh sách
• Tìm một phần tử trong danh sách theo một điều kiện nào đó
• Sắp xếp danh sách theo một điều kiện nào đó

a. Tạo một danh sách rỗng


Thao tác thực hiện :
Thao tác này sẽ khởi tạo một danh sách kép rỗng ban đầu.
Khởi gán địa chỉ của phần tử đầu tiên và địa chỉ của phần tử cuối cùng trong danh sách đều là
NULL
Hàm cài đặt:
void CreateDList(DList &l)
{
l.DHead=NULL;
l.DTail=NULL;
}

b. Tạo một phần tử có thành phần dữ liệu là X


Thao tác thực hiện
Thao tác này sẽ tạo một phần tử mới và gán thành phần dữ liệu là X và chuẩn bị cho thao tác
thêm vào trong danh sách. Hàm trả về địa chỉ phần tử mới tạo.
Nếu (p!=NULL) thì
+ p->Info=X
+ p->Next=NULL
+ p->Pre=NULL
+ return p
Hàm cài đặt
DNode *CreateDNode(int X)
{
DNode *p;
p=new DNode;
if (p==NULL)
{ printf("khong con du bo nho");
exit(1);
}
else
{ p->Info=X;
p->pNext=NULL;
p->pPre=NULL;
return p;
}
}

c. Thêm một phần tử vào đầu danh sách


Thao tác thực hiện
Thao tác này sẽ thực hiện thêm một phần tử vào đầu danh sách đang có và cập nhật lại phần tử
mới thêm vào là phần tử đầu của danh sách mới.

Nếu danh sách rỗng thì

+ Head = p

+ Tail = Head

Ngược lại

+ p->Next = Head

+ Head->Pre=p

+ Head = p
Hàm cài đặt
void AddFirst(Dlist &l, Dnode *p)
{
if (l.pHead==NULL) // danh sách rỗng
{ l.pHead=p;
l.pTail=l.pHead;
}
else
{ p->pNext=l.pHead;
l.pHead->pPre=p;
l.pHead=p;
}
}

d. Thêm vào cuối danh sách


Thao tác thực hiện
Thao tác này sẽ thực hiện thêm một phần tử vào cuối danh sách đang có và cập nhật lại phần tử
mới thêm vào là phần tử cuối của danh sách mới.

Nếu danh sách rỗng thì

+ Head = p

+ Tail = Head

Ngược lại

+ p->Pre=Tail

+ Tail->Next=p

+ Tail=p

Hàm cài đặt


void AddEnd(DList &l,DNode *p)
{
if (l.pHead==NULL)
{ l.pHead=p;
l.pTail=l.pHead;
}
else
{ p->pPre=l.pTail;
l.pTail->pNext=p;
l.pTail=p;
}
}
e. Thêm vào sau phần tử q cho trước trong danh sách
Thao tác thực hiện :
Thao tác thêm một phần tử vào sau phần tử q cho trước trong danh sách thực hiện chèn một
phần tử mới vào giữa 2 phần tử trong danh sách đang có, khi đó các mối liên kết giữa 2 phần tử này
sẽ thay đổi. Trong trường hợp phần tử q là phần tử cuối trong danh sách thì phần tử mới thêm vào sẽ
trở thành phần tử cuối mới trong danh sách, sau khi tiến hành thao tác thêm.

temp=q->pNext

Nếu (q!=NULL) thì


+ p->pNext=temp
+ p->pPre=q
+ q->pNext=tam
+ Nếu (temp!=NULL)
temp->pPre=p
+ Nếu (q==l.pTail) //thêm vào sau danh sách
l.pTail=p
Hàm cài đặt

void AddLastQ(DList &l,DNode *p, DNode *q)


{
DNode *p;
temp=q->pNext;
if (q!=NULL)
{ p->pNext=temp;
p->pPre=q;
q->pNext=tam;
if (temp!=NULL)
temp->pPre=p;
if (q==l.pTail) //thêm vào cuối danh sách
l.pTail=p;
}
else // nếu q là NULL, tức danh sách rỗng, tiến hành gọi hàm
thêm vào đầu danh sách
AddFirst(l,p);
}
f. Thêm vào trước phần tử q cho trước trong danh sách
Thao tác thực hiện
Thao tác thêm một phần tử vào trước nút phần tử cho trước trong danh sách thực hiện chèn một
phần tử mới vào giữa 2 phần tử trong danh sách đang có, khi đó các mối liên kết giữa 2 phần tử này
sẽ thay đổi. Trong trường hợp phần tử q là phần tử đầu trong danh sách thì phần tử mới thêm vào sẽ
trở thành phần tử đầu mới trong danh sách, sau khi tiến hành thao tác thêm.

temp=q->Pre;

Nếu (q!=NULL) thì


+ p->Next=q
+ q->Pre=p
+ p->Pre=temp
+ Nếu (temp!=NULL) thì
temp->Next=tam
+ Nếu (q==Head)
Head = p

Hàm cài đặt :


void AddBeforeQ(DList &l,DNode *p,DNode *q)
{
DNode *p;
temp=q->pPre;
if (q!=NULL)
{ p->pNext=q;
q->pPre=p;
p->pPre=temp;
if (temp!=NULL)
temp->pNext=p;
if (q==l.pHead)
l.pHead = p;
}
else // nếu q là NULL, tức danh sách rỗng, tiến hành gọi hàm
thêm vào đầu danh sách
AddFirst(l,p);
}
g. Hủy phần tử đầu danh sách
Thao tác thực hiện
Thao tác này thực hiện xóa một phần tử đứng đầu danh sách. Sau khi thực hiện thao tác hủy, ta
sẽ cập nhật lại phần tử đứng đầu danh sách là phần tử kế tiếp của phần tử đã xóa khỏi danh sách.
Nguyên tắc khi hủy là phải thực hiện cô lập phần tử cần hủy trước khi hủy.

Nếu (Head!= NULL) thì


+ p=Head
+ Head=Head->Next
+ Head->Pre=NULL
+ delete p
Hàm cài đặt
void DeleteFirst(DList &l)
{
DNode *p;
if(l.pHead!=NULL)
{ p=l.pHead;
l.pHead=l.pHead->pNext;
l.pHead->pPre=NULL;
delete p;
if (l.pHead==NULL)
l.pTail=NULL;
}
}

h. Hủy nút cuối danh sách


Thao tác thực hiện
Thao tác hủy phần tử cuối trong danh sách thực hiện xóa một phần tử đứng cuối danh sách. Sau
khi thực hiện thao tác hủy, ta sẽ cập nhật lại phần tử đứng cuối danh sách mới là phần tử đứng trước
của phần tử đã xóa khỏi danh sách. Nguyên tắc khi hủy là phải thực hiện cô lập phần tử cần hủy
trước khi hủy.

Nếu (Head!=NULL) thì // danh sách có hơn một phần tử


+ p= Tail
+ Tail=Tail->Pre
+ Tail->Next=NULL
+ delete p
Hàm cài đặt
void DeleteEnd(Dlist &l )
{
Dnode *p;
if (l.pHead!=NULL)
{ p=l.pTail ;
l.pTail=l.pTail->Pre ;
l.pTail->pNext=NULL;
delete p;
if (l.pTail==NULL)
l.pHead=NULL;
}
}
i. Hủy một phần tử sau phần tử q cho trước
Thao tác thực hiện
Thao tác hủy thực hiện hủy một phần tử đứng sau phần tử q cho trước trong danh sách đang có,
khi đó các mối liên kết giữa phần tử q và phần tử đứng sau q sẽ thay đổi.
Nếu (q!=NULL) thì
+ p=q->Next
+ Nếu (p!=NULL) thì
q->Next=p->Next
Nếu p là nút cuối thì
Tail=q
Ngược lại
p->Next->Pre=q;
delete p
Hàm cài đặt
void DeleteLastQ(DList &l,DNode *q)
{
DNode *p; //lưu phần tử đứng sau phần tử q
if (q!=NULL)
{ p=q->pNext;
if(p!=NULL)
{ q->pNext=p->pNext;
if (p==l.pTail)
l.pTail=q;
else
p->pNext->pPre=q;
delete p;
}
}
else
DeleteFirst(l);
}
j. Huỷ một phần tử đứng trước phần tử q
Thao tác thực hiện
Thao tác hủy thực hiện hủy một phần tử đứng trước phần tử q cho trước trong danh sách đang
có, khi đó các mối liên kết giữa phần tử q và phần tử đứng trước q sẽ thay đổi.

Nếu (q!= NULL) thì // nếu tồn tại nút q


+ p=q->Pre
+ Nếu (p!=NULL) thì
q->Pre=p->Pre
Nếu là nút đầu danh sách thì
Head=q
Ngược lại
(p->pPre)->pNext=q
delete p
Hàm cài đặt
void DeleteBeforeQ(Dlist &l,Dnode *q)
{
Dnode *p;
if (q!=NULL) // nếu tồn tại nút q
{
p=q->pPre;
if (p!=NULL)
{
q->pPre=p->pPre;
if (p==l.pHead)
l.pHead=q;
else
(p->pPre)->pNext=q;
delete p;
}
}
else
DeleteEnd(l);
}

k. Hủy một phần tử có khoá bằng x


Thao tác thực hiện
Thao tác hủy một phần tử có khoá bằng x cho trước trong danh sách được thực hiện qua các
bước như sau :
 Bước 1 : Duyệt danh sách và tìm phần tử có thành phần Info bằng x
 Bước 2 :
Nếu có tìm thấy phần tử có khóa bằng x thì
 Nếu phần tử cần hủy nằm ở đầu danh sách thì
Gọi hàm hủy phần tử ở đầu danh sách
 Ngược lại nếu phần tử cần hủy nằm ở cuối danh sách thì
Gọi hàm hủy phần tử ở cuối danh sách
Ngược lại :
Gọi hàm hủy phần tử sau q hoặc trước q
Ngược lại :
Thông báo không có phần tử bằng x trong danh sách
Hàm cài đặt
int DeleteX(DList &l,int x)
{ DNode *p;
DNode *q;
q=NULL;
p=l.pHead;
while (p!=NULL)
{ if (p->Info==x) break;
q=p; //q là nút có thành phần Info = x
p=p->pNext;
}
if (q==NULL)
return 0; //không tìm thấy nút có thành phần Info = x
if (q!=NULL)
if (q==l.pTail)
DeleteLastQ(l,q);
else if (q==l.pHead)
DeleteFirst(l,q);
else DeleteAfterQ(l,q);
return 1;
}

You might also like