Tải bản đầy đủ (.docx) (34 trang)

Tiểu luận Cấu trúc dữ liệu và giải thuật Đề tài: Nghiên cứu và cài đặt chương trình thực hiện các phép toán bổ sung và loại bỏ phần tử đối với danh sách móc nối đơn và danh sách móc nối kép

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (174.61 KB, 34 trang )

Lời nói đầu
******
Ngày nay, nền khoa học kĩ thuật ngày càng phát triển, đặc biệt là ngành công nghệ
thông tin. Ứng dụng của công nghệ đã tràn ngập mọi mặt trong đời sống. Từ vật
chất như điện thoại, tivi, tủ lạnh, điều hòa, điều khiển máy … tới các mạng xã hội
như facebook, zalo, google ….tất cả đều là ứng dụng của công nghệ thông tin. Thế
giới ngày càng hiện đại là do nghành công nghệ thông tin ngày càng phát triển.
Chính vì tầm quan trọng và đa dạng của ngành công nghệ thông tin mà đòi hỏi các
sinh viên công nghệ thông tin cần phải nắm vững các nguyên lý và ứng dụng của
của các môn học công nghệ thông tin nói chung và môn cấu trúc dữ liệu và giải
thuật nói riêng .Môn học trang bị cho sinh viên những kiến thức cơ bản về cấu trúc
dữ liệu khi thiết kế và cài đặt các phần mềm. Trong phạm vi môn học, nhằm tìm
hiểu về danh sách liên kết ,tác giả xin trình bày đề tài: Nghiên cứu và cài đặt
chương trình thực hiện các phép toán bổ sung và loại bỏ phần tử đối với danh sách
móc nối đơn và danh sách móc nối kép

Giới thiệu đề tài.

I.
1.

2.

Phát biểu để tài:
Nghiên cứu và cài đặt chương trình thực hiện các phép toán bổ sung và loại
bỏ phần tử đối với danh sách móc nối đơn và danh sách móc nối kép
Đối tượng:

- Danh sách liên kết đơn.
- Danh sách liên kết kép.
3.



Mục tiêu:


- Tìm hiểu về con trỏ
- tìm hiểu về cấu trúc dữ liệu của danh sách liên kết đơn
- Tìm hiểu về cấu trúc của danh sách liên kết kép
- Tìm hiểu về thuật toán chương trình được sử dụng khi cài đặt bài toán loại bỏ, bổ
sung phần tử trên danh sách liên kết đơn , danh sách liên kết kép , ghép danh sách
liên kết đơn, ghép danh sách liên kết kép.
4. Phạm vi:
- Nghiên cứu lý thuyết môn học “Cấu trúc dữ liệu và giải thuật”.
- Nghiên cứu trọng tâm lý thuyết lý thuyết về dữ liệu con trỏ .
- Nghiên cứu trọng tâm lý thuyết về danh sách liên kết đơn , danh sách liên kết kép
- Cài đặt chương trình thực hiện các phép toán bổ sung và loại bỏ phần tử đối với
danh sách móc nối đơn và danh sách móc nối kép, ghép 2 danh sách liên kết đơn,
danh sách liên kết kép.
5. Phương pháp nghiên cứu :
- Nghiên cứu lý thuyết từ giáo trình môn học “Cấu trúc dữ liệu và giải thuật” và
“giáo trình lập trình C++” , tìm hiểu tài liệu từ các nguồn thông tin web , từ đó viết
các chương trình trên C++, chạy thử và kiểm tra đọ chính xác của chương trình .

II. Lý thuyết.
1

Danh sách liên kết

Danh sách liên kết là danh sách mà các phần tử được liên kết với nhau nhờ vào
vùng liên kết của chúng
Mỗi phần tử của danh sách được lưu trữ trong 1 phần tử nhớ gồm một số đơn vị

bộ nhớ kế tiếp nhau được gọi là nút
Mỗi nút có 2 thành phần :
+ Trường dữ liệu : Lưu trữ thông dữ liệu của nút


+ Trường con trỏ : chứa địa chỉ của nút kế tiếp hay trước nó
2

Danh sách liên kết đơn.

a. Khái niệm
-Danh sách liên kết đơn là danh sách mà mỗi phần tử của nó chỉ sử dụng một con
trỏ để tổ chức lưu trữ
b. Khai báo
Mỗi nút gồm 2 trường:
+ Trường dữ liệu: lưu thông tin dữ liệu của nút, trường này có ít nhất một trường
dữ liệu nhỏ
+ Trường con trỏ: chứa địa chỉ của nút đứng sau (trỏ tới nút đứng sau)
A

B

C

D

Các phần tử của danh sách liên kết được chứa ở vùng không gian nhớ không kề
nhau trong bộ nhớ.chúng được nối với nhau nhờ vào vùng liên kết. Vùng liên kết
của phần tử thứ nhất chứa địa chỉ của phần tử thứ hai, cùng liên kết của phần tử thứ
hai chứa địa chỉ của phần tử thứ ba , cứ như thế cho đến phần tử cuối cùng .

Riêng nút cuối cùng (do không có nút sau nó) nên trường con trỏ của nó phải là
một địa chỉ đặc biệt mà ta phải gọi là địa chỉ (con trỏ ) null ( địa chỉ rỗng ).
Để truy cập vào danh sách nối đơn, ta sử dụng một con trỏ L (list) trỏ tới nút đầu
tiên của danh sách.
Khi danh sách rỗng (danh sách không có phần tử nào) thì L=null
-Quy ước các phép toán:
+ X<= AVAIL : phép xin cấp phát 1 nút X từ danh sách chỗ trống hay phép xin 1
nút từ danh sách chỗ trống có địa chỉ X
+ X=> AVAIL : Phép thu hồi một nút X hay phép trả 1 có địa chỉ X về danh sách
chỗ trống


- Quy ước về việc truy cập một nút
+ Với 1 nút được trỏ bởi con trỏ P:
. dulieu (P) : chỉ trường dữ liệu của nút P
.contro (P): chỉ trường con trỏ của nút P
Riêng nút cuối cùng thì không có nút đứng sau nên ta quy ước trường con trỏ của
nó là null
Ví dụ danh sách khách hàng có số điện thoại tăng dần được chứa trong một danh
sách như sau:
Vị trí
0000
0022
0033
0044
0055

Họ tên khách hàng
Nguyễn Thị Linh
Kim Thị Hải Hà

Nguyễn Thị Trang
Nguyễn Thị Hằng
Đinh Thị Oanh

Điện thoại
8631517
8632875
8643296
8655782
8678431

Liên kết
0055
0033
Null
0000
0022

Với cách tổ chức như trên thì khi loại bỏ một phần tử ta chỉ cần thay đổi vùng liên
kết của phần tử đứng ngay trước đó (theo liên kết) chỉ đến phần tử đứng ngay sau
đó.
c. Các giải thuật đặc trưng của danh sách liên kết đơn.
Cho L là con trỏ cực trái và R là con trỏ cực phải của một danh sách
liên kết kép.
M là con trỏ, tỏ vào mộ nút tron danh sách này.
Lập giải thuật bổ sung một nút mới vào trước nút M, dữ liệu của nút mới là X.

3. Danh sách liên kết kép.
a. Khái niệm.



- Danh sách liên kết kép là danh sách mà mỗi phần tử trong danh sách có kết nối
với một phần tử đứng trước và một phần tử đứng sau nó.
Danh sách liên kết kép được xác định bởi hai con trỏ:
- left trỏ vào node đầu tiên.
- right trỏ vào node cuối cùng.

b. Khai báo.
Danh sách nối kép gồm các nút được nối với nhau theo 2 chiều. Mỗi nút là mọt bản
ghi (record) gồm ba trường:
- Trường thứ nhất chứa giá trị lưu trong nút đó.
- Trường thứ hai (Next) chứa liên kết (con trỏ) tới nút kế tiếp, tức là chứa một
thông tin đủ để biết nút kế tiếp nút đó là nút nào, trong trường hợp là nút cuối cùng
(không có nút kế tiếp), trường liên kết này được gán một giá trị đặc biệt.
- Trường thứ ba (Prev) chứa liên kết (con trỏ) tới nút liền trước, tức là chứa một
thông tin đủ để biết nút đứng trước nút đó trong danh sách là nút nào, trong trường
hợp là nút đầu tiên (không có nút liền trước) trường này được gán một giá trị đặc
biệt.

Liên kết sau
Data
.

Giá trị
Liên kết trước

Khác với danh sách nối đơn, danh sách nối kép có hai chốt:
- Nút đầu tiên trong danh sách được gọi là First.
- Nút cuối cùng trong danh sách được gọi là Last.
Để duyệt danh sách nối kép, ta có hai cách:



- Hoặc bắt đầu từ First, dựa vào liên kết Next để sang nút kế tiếp, đến khi
gặp giá trị đặc biệt (duyệt qua nút cuối) thì dừng lại.
- Hoặc bắt đầu từ Last, dựa vào liên kết Prev để đi sang nút liền trước. Việc
chèn / xóa vào danh sách nối kép cũng đơn giản chỉ là kỹ thuật chỉnh lại các mối
liên kết giữa các nút cho hợp lý.
Việc chèn / xóa vào danh sách nối kép cũng đơn giản chỉ là kỹ thuật chỉnh lại
các mối liên kết giữa các nút cho hợp lý.
Ví dụ cần in danh sách theo thứ tự số điện thoại thì ta duyệt theo liên kết thứ
hai:
Vị trí
0000
0022
0033
0044
0055

Họ tên khách hàng
Kim Hải Hà
Nguyễn Thu Hằng
Nguyễn Thị Linh
Đinh Thị Oanh
Phạm Thị Trang

Điện thoại
8632215
8633341
8674532
8681123

8694567

Liên kết 1
0110
Nil
0000
0022
0044

Liên kết 2
0055
0110
Nil
0000
0022

Tổ chức danh sách liên kết kép:
Trong mỗi nút ngoài phần Data còn có hai con trỏ: một trỏ đến nút đứng
trước nó và một trỏ đến nút đứng sau.
Như vậy cấu trúc mỗi nút sẽ đưuọc biểu diễn như sau:
Lptr

Data

Trong đó:
Data chứa số dữ liệu của nút.
Lptr: con trỏ trái, trỏ tới nút đứng trước.
Rptr: con trỏ phải, trỏ tới nút đứng sau.
Lptr của nút cực trái và Rptr của nút cực phải là Nil.
c. Các giải thuật dặc trưng cơ bản.


Rptr


Cho L là con trỏ cực trái và R là con trỏ cực phải của một danh sách liên kết
kép.
M là con trỏ, tỏ vào mộ nút tron danh sách này.
Lập giải thuật bổ sung một nút mới vào trước nút M, dữ liệu của nút mới là
X.

III. Cơ sở CTDL và GT
1.

a.

Danh sách móc nối đơn.
a. Phép bổ sung thêm một phần tử vào danh sách nối đơn
BÀI TOÁN: Cho một danh sách nối đơn L. Viết giải thuật bổ sung
thêm 1 phần tử New có trường dữ liệu lấy từ ô nhớ có địa chỉ X vào
sau nút trỏ bởi M trong danh sách nối đơn.
GIẢI THUẬT:
Void LInset(L, M, X)
1. { Xin cấp phát nút mới}
New AVAIL;
Dulieu(New)= X;
2. { Bổ sung}
If (L== null){ danh sách rỗng}
{
L= New;
Contro(New):= null;

}
Else {trường hợp tổng quát}
{
Contro(New)= contro(M);
Contro(M)= New;
}
3. Return;
Phép loại bỏ 1 phần tử khỏi danh sách nối đơn
BÀI TOÁN: Cho danh sách nối đơn L, viết giải thuật loại bỏ 1 nút trỏ
bởi M trong danh sách nối đơn trên.
GIẢI THUẬT:
Void LDelete(L, M)
1. {kiểm tra danh sách có rỗng không}
If (L== null)
{


b.

2.
a.

Printf(“ danh sách rỗng”);
Return;
}
2. {loại bỏ}
If M= L
{
L= contro(M);
M AVAIL;

}
Else
{
P= L;
While (contro(P) != M)
P= contro(P);
Contro(P)= Contro(M);
}
3. MAVAIL;
4. Return;
Phép ghép hai danh sách nối đơn thành một danh sách mới.
BÀI TOÁN: Cho 2 danh sách nối đơn P, Q. Viết giải thuật ghép 2
danh sách trên thành một danh sách và cho P trỏ tới nút đầu tiên của
danh sách kết quả.
GIẢI THUẬT:
Procedure GHEP(P, Q)
1. If (Q== null)
Return;
2. If (P== null)
P= Q;
3. If (P!= null) and (Q!=null)
{
P1= P;
While (contro(P)!=null)
P1:= contro(P1);
Contro(P1):= Q;
}
4. Return;
Danh sách móc nối kép
Giải thuật bổ sung thêm một nút vào danh sách nối kép



b.

BÀI TOÁN: Cho danh sách nối kép L, R. hãy viết giải thuật bổ sung
thêm một phần tử New có trường dữ liệu lấy từ ô nhớ có địa chỉ X tử
danh sách vào trước nút trỏ bởi M.
GIẢI THUẬT:
Void DLInsert(L, R, M, X)
1. { Xin cấp phát nút}
New AVAIL;
Dulieu(New)=X;
2. {Bổ sung vào danh sách rỗng}
If (L==null)
{
L=R= New;
Trotruoc(New)=trosau(New)= null;
}
3. {Bổ sung thêm đầu dãy}
If (M==L)
{
Trotruoc(New)= null;
Trosau(New)=M;
Trotruoc(M)= New;
L=New;
}
4. {tổng quát}
Else
{
Trotruoc(New)= trotruoc(M);

Trosau(New)= M;
Trotruoc(M)=New;
Trosau(trotruoc(New))= New;
}
5. Return;
Giải thuật loại bỏ một phần tử ra khỏi DS nối kép
BÀI TOÁN: Cho DS nối kép L, R. Hãy viết giải thuật loại bỏ 1 nút M
khỏi DS trên
GIẢI THUẬT:
Void DLDetele(L,R,M)
1. {Kiểm tra xem danh sách rỗng không}
If (L==null)
{


c.

1.

2.

Printf(“Danh sách rỗng”);
Return;
}
2. {loại bỏ}
If (L==R){danh sách bị rỗng sau khi loại bỏ}
L=R=null;
If (M==L){ loại bỏ nút cực trái}
{
L= trosau(M);

Trotruoc(L)= null;
}
If (M==R){ loại bỏ nút cực phải}
{
R= trotruoc(M);
Trosau(R)= null;
}
Else
{
Trosau(trotruoc(M))= trosau(M);
Trotruoc(trosau(M))= trotruoc(M);
}
3. MAVAIL;
4. Return;
Giải thuật ghép hai danh sách móc nối kép
BÀI TOÁN: Cho 2 danh sách nối kép P, Q. Viết giải thuật ghép 2
danh sách trên thành một danh sách.
GIẢI THUẬT:
Procedure GHEP(P1, Q1, P2,Q2)
If (P1== null) and (Q1==null)
{
Printf(“Danh sách thứ nhất rỗng”);
P=P2;
Q=Q2;
}
If (P2==null) and (Q2==null)
{
Printf(“Danh sách thứ 2 rỗng”);
P=P1;
Q=Q1;

}


3.

4.

If (P!= null) and (Q!=null)
{
P=P1;
Q=Q2;
Trotrai(Q1)=P2;
Trophai(L2)=Q1;
}
Return;

IV. Chương trình.
1.

Bổ sung và loại bỏ trong danh sách nối đơn:
#include<stdio.h>
#include<stdlib.h>
typedef int item;
typedef struct Node //Cau truc cua 1 Node
{
item Data;
//Du lieu cua Node
Node *next; //Con tro cua Node
};
typedef Node *List; //List la mot danh sach cac Node

void Init (List &L); //khoi tao danh sach rong
int len (List L); // Do dai danh sach
Node *Make_Node (Node *P, item x); //Tao 1 Node P voi thong tin
chu trong no
void Insert_first (List &L, item x); //Chen phan tu vao dau danh sach
void Insert_k (List &L, item x, int k); //Chen phan tu vao vi tri k trong
danh sach
void Input (List &L); //Nhap danh sach
void Output (List L); //Xuat danh sach
int Search (List L, item x); //Tim phan tu x trong danh sach, ham tra
ve vi tri cua phan tu tim duoc
void Del_frist (List &L, item &x); //Xoa phan tu dau danh sach
void Del_k (List &L, item &x, int k); //Xoa phan tu vi tri k trong
danh sach
void Del_x (List &L, item x); //Xoa phan tu co gia tri x trong danh
sach
void Init (List &L) // &L lay dia chi cua danh sach ngay khi truyen
vao ham


{
L=NULL; //Cho L tro den NULL
}
int Isempty (List L)
{
return (L==NULL);
}
int len (List L)
{
Node *P=L; //tao 1 Node P de duyet danh sach L

int i=0; //bien dem
while (P!=NULL) //trong khi P chua tro den NULL (cuoi danh sach
thi lam)
{
i++; //tang bien dem
P=P->next; //cho P tro den Node tiep theo
}
return i; //tra lai so Node cua l
}
Node *Make_Node (Node *P, item x) //tao 1 Node P chua thong tin la
x
{
P = (Node *) malloc (sizeof (Node)); //Cap phat vung nho cho P
P->next = NULL; //Cho truong Next tro den NULL
P->Data = x; //Ghi du lieu vao Data
return P;
}
void Insert_first (List &L, item x) //Chen x vao vi tri dau tien trong
danh sach
{
Node *P;
P = Make_Node(P,x); //tao 1 Node P
P->next = L; //Cho P tro den L
L = P; //L tro ve P
}


void Insert_k (List &L, item x, int k) //chen x vao vi tri k trong danh
sach
{

Node *P, *Q = L;
int i=1;
if (k<1 || k> len(L)+1) printf("Vi tri chen khong hop le !"); //kiem
tra dieu kien
else
{
P = Make_Node(P,x); //tao 1 Node P
if (k == 1) Insert_first(L,x); //chen vao vi tri dau tien
else //chen vao k != 1
{
while (Q != NULL && i != k-1) //duyet den vi tri k-1
{
i++;
Q = Q->next;
}
P->next = Q->next;
Q->next = P;
}
}
}
int Search (List L, item x) //tim x trong danh sach
{
Node *P=L;
int i=1;
while (P != NULL && P->Data != x) //duyet danh sach den khi tim
thay hoac ket thuc danh sach
{
P = P->next;
i++;
}

if (P != NULL) return i; //tra ve vi tri tim thay
else return 0; //khong tim thay
}
void Del_frist (List &L, item &x) //Xoa phan tu dau tien


{
x = L->Data; //lay gia tri ra neu can dung
L = L->next; //Cho L tro den Node thu 2 trong danh sach
}
void Del_k (List &L, item &x, int k) //Xoa Node k trong danh sach
{
Node *P=L;
int i=1;
if (k<1 || k>len(L)) printf("Vi tri xoa khong hop le !"); //kiem tra
dieu kien
else
{
if (k==1) Del_frist(L,x); //xoa vi tri dau tien
else //xoa vi tri k != 1
{
while (P != NULL && i != k-1) //duyet den vi tri k-1
{
P=P->next;
i++;
}
P->next = P->next->next; //cho P tro sang Node ke tiep vi tri k
}
}
}

void Del_x (List &L, item x) //xoa phan tu x trong danh sach
{
while (Search(L,x)) Del_k (L,x,Search(L,x)); //trong khi van tim
thay x thi van xoa
}
void Input (List &L) //nhap danh sach
{
int i=0;
item x;
do
{
i++;
printf ("Nhap phan tu thu %d : ",i);


scanf("%d",&x);
if (x != 0) Insert_k(L,x,len(L)+1);
} while(x != 0); //nhap 0 de ket thuc
}
void Output (List L) //xuat danh sach
{
Node *P=L;
while (P != NULL)
{
printf("%5d",P->Data);
P = P->next;
}
printf("\n");
}
int main()

{
List L;
Init(L);
Input(L);
Output(L);
int lua_chon;
printf("Moi ban chon phep toan voi DS LKD:");
printf("\n1: Kiem tra DS rong");
printf("\n2: Do dai DS");
printf("\n3: Chen phan tu x vao vi tri k trong DS");
printf("\n4: Tim mot phan tu trong DS");
printf("\n5: Xoa phan tu tai vi tri k");
printf("\n6: Xoa phan tu x trong DS");
printf("\n7: Thoat");
do
{
printf("\nBan chon: ");
scanf("%d",&lua_chon);
switch (lua_chon)
{
case 1:
{


if (Isempty(L)) printf("DS rong !");
else printf ("DS khong rong !");
break;
}
case 2: printf ("Do dai DS la: %d.",len(L));break;
case 3:

{
item x;
int k;
printf ("Nhap phan tu can chen vao DS: ");
scanf("%d",&x);
printf ("Nhap vi tri can chen: ");
scanf ("%d",&k);
Insert_k (L,x,k);
printf ("DS sau khi chen:\n");
Output(L);
break;
}
case 4:
{
item x;
printf ("Moi ban nhap vao phan tu can tim: ");
scanf("%d",&x);
int k=Search(L,x);
if (k) printf ("Tim thay %d trong DS tai vi tri thu: %d",x,k);
else printf ("Khong tim thay %d trong danh sach !",x);
break;
}
case 5:
{
int k;
item x;
printf ("Nhap vi tri can xoa: ");
scanf ("%d",&k);
Del_k (L,x,k);
printf ("DS sau khi xoa:\n");

Output(L);
break;
}
case 6:


{
item x;
printf ("Nhap phan tu can xoa: ");
scanf ("%d",&x);
Del_x (L,x);
printf ("DS sau khi xoa:\n");
Output(L);
break;
}
case 7: break;
}
}while (lua_chon !=7);
return 0;
2.

}
Ghép 2 danh sách nối đơn:
#include<conio.h>
#include<stdio.h>
#include<ctype.h>
struct node
{
int data;
node *next;

};
struct list
{
node *head;
node *tail;
};
node *getnode(int x)
{
node *p;
p=new(node);
if(p==NULL)
{
printf("\n Khong du bo nho");
return NULL;
}
p->data=x;


p->next=NULL;
return p;
}
void Init(list &l)
{
l.head=l.tail=NULL;
}
void addtail(list &l,node *new_e)
{
if(l.head==NULL)
{
l.head=l.tail=new_e;

}
else
{
l.tail->next=new_e;
l.tail=new_e;
}
}
void nhap(list &l)
{
int i,n,x;
node *p;
printf("\n nhap so luong phan tu danh sach 1: ");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
printf("\n a[%d]= ",i);
scanf("%d",&x);
p=getnode(x);
addtail(l,p);
}
printf("\n nhap so luong phan tu danh sach 2: ");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
printf("\n a[%d]= ",i);
scanf("%d",&x);
p=getnode(x);


addtail(l,p);

}
}
void xuat(list &l)
{
printf("\n Danh sach sau khi ghep la: \n");
node *p;
p=l.head;
while(p!=NULL)
{
printf("%d
",p->data);
p=p->next;
}

3.

}
int main()
{
list l;
node *p;
Init(l);
nhap(l);
xuat(l);
getch();
}
Bổ sung và loại bỏ danh sách nối kép:
#include <stdlib.h>
#include <stdio.h>
typedef int item;

typedef struct Node //cau truc 1 Node
{
item Data; //du lieu cua Node
Node *Left; //Con tro trai
Node *Right; //con tro phai
};
typedef struct DList //cau truc Cua List
{
Node *Head; //con tro dau


Node *Tail; //con tro cuoi
};
void Init(DList &L); //Khoi tao DS rong
int Isempty (DList L); //kiem tra DS co rong hay khong
int Len (DList L); // Do dai danh sach
Node *Make_Node (Node *P, item x); //tao 1 Node P chua thong tin
la x
void Insert_first (DList &L, item x); //Chen x vao vi tri dau tien trong
danh sach
void Insert_last (DList &L, item x); //Chen x vao vi tri dau tien trong
danh sach
void Insert_k (DList &L, item x, int k); //chen x vao vi tri k trong
danh sach
void Del_first (DList &L, item &x); //Xoa phan tu dau tien
void Del_k (DList &L, item &x, int k); //Xoa Node k trong danh sach
int Search (DList L, item x); //tim x trong danh sach
void Del_x (DList &L, item x); //xoa phan tu x trong danh sach
void Input (DList &L); //nhap danh sach
void Output (DList L); //xuat danh sach

void Init(DList &L)
{
L.Head = NULL; // Con tro dau tro den NULL
L.Tail = NULL; // Con tro cuoi tro den NULL
}
int Isempty (DList L) //kiem tra DS rong
{
return (L.Head == NULL);
}
int Len (DList L) // Do dai danh sach
{
Node *PH = L.Head, *PT = L.Tail; //tao Node PH (con tro duyet tu
dau DS) và PT (con tro duyet tu cuoi DS) de duyet danh sach L
int i = 0; //bien dem
if (PH != NULL) i = 1;


while (PH != NULL) //trong khi P chua tro den NULL (cuoi danh
sach thi lam)
{
if (PH == PT) break;
PH = PH->Right; //cho PH tro den Node tiep theo
i++;
if (PH == PT) break;
PT = PT->Left; //cho PT tro den Node truoc do
i++;
}
return i; //tra lai so Node cua L
}
Node *Make_Node (item x) //tao 1 Node P chua thong tin la x

{
Node *P = (Node *) malloc (sizeof (Node)); //Cap phat vung nho
cho P
P->Data = x; //Ghi du lieu vao Data
P->Left = NULL;
P->Right = NULL;
return P;
}
void Insert_first (DList &L, item x) //Chen x vao vi tri dau tien trong
danh sach
{
Node *P;
P = Make_Node(x); //tao 1 Node P
if (Isempty(L)) //Neu danh sach rong
{
L.Head = P;
L.Tail = P;
}
else
{
P->Right = L.Head;
L.Head->Left = P;
L.Head = P;
}
}


//Chen vao cuoi danh sach cung tuong tu
void Insert_last (DList &L, item x) //Chen x vao vi tri cuoi trong
danh sach

{
Node *P;
P = Make_Node(x); //tao 1 Node P
if (Isempty(L)) //Neu danh sach rong
{
L.Head = P;
L.Tail = P;
}
else
{
L.Tail->Right = P; //ket noi voi danh sach
P->Left = L.Tail; //P tro ve Node truoc
L.Tail = P; //luu lai vi tri cuoi
}
}
void Insert_k (DList &L, item x, int k) //chen x vao vi tri k trong danh
sach
{
Node *PH = L.Head, *PT, *R;
int i=1, l = Len(L);
if (k<1 || k> l+1) printf("Vi tri chen khong hop le !"); //kiem tra
dieu kien
else
{
R = Make_Node(x); //tao 1 Node P
if (k == 1) Insert_first(L,x); //chen vao vi tri dau tien
else
if (k == l+1) Insert_last(L,x); //chen vao vi tri cuoi
else //chen vao vi tri 1{

while (PH != NULL && i != k-1) //duyet den vi tri k-1
{
i++;
PH = PH->Right;
}


PT = PH->Right; //xac dinh vi tri k
R->Right = PT; //(1)
R->Left = PH; //(2)
PH->Right = R; //(3)
PT->Left = R; //(4)
}
}
}
void Del_first (DList &L, item &x) //Xoa phan tu dau tien
{
if (!Isempty(L))
{
x = L.Head->Data; //lay gia tri ra neu can dung
L.Head = L.Head->Right; //Cho L tro den Node thu 2 trong danh
sach
}
}
void Del_last (DList &L, item &x) //Xoa phan tu dau tien
{
if (!Isempty(L))
{
x = L.Tail->Data;
L.Tail = L.Tail->Left;

L.Tail->Right = NULL;
}
}
void Del_k (DList &L, item &x, int k) //Xoa Node k trong danh sach
{
Node *PH = L.Head, *PT;
int i=1, l = Len(L);
if (k<1 || k> l) printf("Vi tri xoa khong hop le !"); //kiem tra dieu
kien
else
{
if (k == 1) Del_first(L,x); //xoa vi tri dau tien
else
if (k == l) Del_last(L,x); //xoa vi tri cuoi


else //xoa vi tri 1{
while (PH != NULL && i != k-1) //duyet den vi tri k-1
{
i++;
PH = PH->Right;
}
x = PH->Right->Data;
PT = PH->Right->Right; //xac dinh vi tri k+1
PH->Right = PT;
PT->Left = PH;
}
}
}

int Search (DList L, item x) //tim x trong danh sach
{
Node *P=L.Head;
int i=1;
while (P != NULL && P->Data != x) //duyet danh sach den khi tim
thay hoac ket thuc danh sach
{
P = P->Right;
i++;
}
if (P != NULL) return i; //tra ve vi tri tim thay
else return 0; //khong tim thay
}
void Del_x (DList &L, item x) //xoa phan tu x trong danh sach
{
int l = Search(L,x);
while (l)
{
Del_k (L,x,l); //trong khi van tim thay x thi van xoa
l = Search(L,x);
}
}


void Input (DList &L) //nhap danh sach
{
int i=0;
item x;
do
{

i++;
printf ("Nhap phan tu thu %d : ",i);
scanf("%d",&x);
if (x != 0) Insert_k(L,x,Len(L)+1);
} while(x != 0); //nhap 0 de ket thuc
}
void Output (DList L) //xuat danh sach
{
Node *P=L.Head;
while (P != L.Tail->Right)
{
printf("%5d",P->Data);
P = P->Right;
}
printf("\n");
}
int main()
{
DList L;
Init(L);
Input(L);
Output(L);
int lua_chon;
printf("Moi ban chon phep toan voi DS LKD:");
printf("\n1: Kiem tra DS rong");
printf("\n2: Do dai DS");
printf("\n3: Chen phan tu x vao vi tri k trong DS");
printf("\n4: Tim mot phan tu trong DS");
printf("\n5: Xoa phan tu tai vi tri k");
printf("\n6: XOa phan tu x trong DS");

printf("\n7: Thoat");


×