1.6k likes | 1.76k Views
CHAPTER 6: LINKED LISTS. Cấu trúc dữ liệu động. Mục tiêu. Giới thiệu khái niệm cấu trúc dữ liệu động . Giới thiệu danh sách liên kết : Các kiểu tổ chức dữ liệu theo DSLK . Danh sách liên kết đơn : tổ chức , các thuật toán , ứng dụng. Kiểu dữ liệu tĩnh.
E N D
Mụctiêu • Giớithiệukháiniệmcấutrúcdữliệuđộng. • Giớithiệudanhsáchliênkết: • CáckiểutổchứcdữliệutheoDSLK. • Danhsáchliênkếtđơn: tổchức, cácthuậttoán, ứngdụng.
Kiểudữliệutĩnh • Khái niệm : Một số đối tượng dữ liệu không thay thay đổi được kích thước, cấu trúc, … trong suốt quá trình sống. Các đối tượng dữ liệu thuộc những kiểu dữ liệu gọi là kiểu dữ liệu tĩnh. • Một số kiểu dữ liệu tĩnh : các cấu trúc dữ liệu được xây dựng từ các kiểu cơ sở như: kiểu thực, kiểu nguyên, kiểu ký tự ... hoặc từ các cấu trúc đơn giản như mẩu tin, tập hợp, mảng ... Các đối tượng dữ liệu được xác định thuộc những kiểu dữ liệu này thường cứng ngắt, gò bó khó diễn tả được thực tế vốn sinh động, phong phú.
CTDLtĩnh–Mộtsốhạnchế • Mộtsốđốitượngdữliệutrongchukỳsốngcủanócóthểthayđổivềcấutrúc, độlớn, nhưdanhsáchcáchọcviêntrongmộtlớphọccóthểtăngthêm, giảmđi ... Nếudùngnhữngcấutrúcdữliệutĩnhđãbiếtnhưmảngđểbiểudiễn Nhữngthaotácphứctạp, kémtựnhiên chươngtrìnhkhóđọc, khóbảotrìvànhấtlàkhócóthểsửdụngbộnhớmộtcáchcóhiệuquả. • Dữliệutĩnhsẽchiếmvùngnhớđãdànhchochúngsuốtquátrìnhhoạtđộngcủachươngtrình sửdụngbộnhớkémhiệuquả.
CTDL tĩnh • Mảng 1 chiều • Kích thước cố định (fixed size) • Chèn 1 phần tử vào mảng rất khó • Các phần tử tuần tự theo chỉ số 0 n-1 • Truy cập ngẫu nhiên (random access) chèn 2 3 4 0 n-2 1 n-1
Cấu trúc dữ liệu động • Danh sách liên kết • Cấp phát động lúc chạy chương trình • Các phần tử nằm rải rác ở nhiều nơi trong bộ nhớ • Kích thước danh sách chỉ bị giới hạn do RAM • Thao tác thêm xoá đơn giản Insert, Delete
Hướnggiảiquyết • Cầnxâydựngcấutrúcdữliệuđápứngđượccácyêucầu: • Linhđộnghơn. • Cóthểthayđổikíchthước, cấutrúctrongsuốtthờigiansống. Cấutrúcdữliệuđộng.
Biếnkhôngđộng Biếnkhôngđộng (biếntĩnh, biếnnửatĩnh) lànhữngbiếnthỏa: • Đượckhaibáotườngminh, • Tồntạikhivàophạmvikhaibáovàchỉmấtkhirakhỏiphạmvinày, • Đượccấpphátvùngnhớtrongvùngdữliệu (Datasegment) hoặclàStack (đốivớibiếnnửatĩnh - cácbiếncụcbộ). • Kíchthướckhôngthayđổitrongsuốtquátrìnhsống. • Dođượckhaibáotườngminh, cácbiếnkhôngđộngcómộtđịnhdanhđãđượckếtnốivớiđịachỉvùngnhớlưutrữbiếnvàđượctruyxuấttrựctiếpthôngquađịnhdanhđó. • Vídụ : inta; // a, blàcácbiếnkhôngđộng charb[10];
Biếnđộng • Trongnhiềutrườnghợp, tạithờiđiểmbiêndịchkhôngthểxácđịnhtrướckíchthướcchínhxáccủamộtsốđốitượngdữliệudosựtồntạivàtăngtrưởngcủachúngphụthuộcvàongữcảnhcủaviệcthựchiệnchươngtrình. • Cácđốitượngdữliệucóđặcđiểmkểtrênnênđượckhaibáonhưbiếnđộng. Biếnđộnglànhữngbiếnthỏa: • Biếnkhôngđượckhaibáotườngminh. • Cóthểđượccấppháthoặcgiảiphóngbộnhớkhingườisửdụngyêucầu. • Cácbiếnnàykhôngtheoquitắcphạmvi (tĩnh). • VùngnhớcủabiếnđượccấppháttrongHeap. • Kíchthướccóthểthayđổitrongquátrìnhsống.
Biếnđộng • Dokhôngđượckhaibáotườngminhnêncácbiếnđộngkhôngcómộtđịnhdanhđượckếtbuộcvớiđịachỉvùngnhớcấpphátchonó, dođógặpkhókhănkhitruyxuấtđếnmộtbiếnđộng. • Đểgiảiquyếtvấnđề, biếncontrỏ (làbiếnkhôngđộng) đượcsửdụngđểtrỏđếnbiếnđộng. • Khitạoramộtbiếnđộng, phảidùngmộtcontrỏđểlưuđịachỉcủabiếnnàyvàsauđó, truyxuấtđếnbiếnđộngthôngquabiếncontrỏđãbiếtđịnhdanh.
Biếnđộng • Haithaotáccơbảntrênbiếnđộnglàtạovàhủymộtbiếnđộngdobiếncontrỏ‘p’trỏđến: • Tạoramộtbiếnđộngvàchocontrỏ‘p’chỉđếnnó • Hủymộtbiếnđộngdopchỉđến
Biếnđộng • Tạoramộtbiếnđộngvàchocontrỏ‘p’chỉđếnnó void* malloc(size);// trảvềcontrỏchỉđếnvùngnhớ // sizebytevừađượccấpphát. void* calloc(n,size);// trảvềcontrỏchỉđếnvùngnhớ // vừađượccấpphátgồmnphầntử, // mỗiphầntửcókíchthướcsizebyte new// toántửcấpphátbộnhớtrongC++ • Hàmfree(p) huỷvùngnhớcấpphátbởihàmmallochoặccallocdoptrỏtới • Toántửdeletephuỷvùngnhớcấpphátbởitoántửnewdoptrỏtới
Biếnđộng–Vídụ int *p1, *p2; // cấpphátvùngnhớcho 1 biếnđộngkiểuint p1 = (int*)malloc(sizeof(int)); *p1 = 5; // đặtgiátrị 5 chobiếnđộngđangđượcp1 quảnlý // cấpphátbiếnđộngkiểumảnggồm 10 phầntửkiểuint p2 = (int*)calloc(10, sizeof(int)); *(p2+3) = 0; // đặtgiátrị 0 chophầntửthứ 4 củamảngp2 free(p1); free(p2);
KiểudữliệuContrỏ • Kiểucontrỏlàkiểucơsởdùnglưuđịachỉcủamộtđốitượngdữliệukhác. • BiếnthuộckiểucontrỏTplàbiếnmàgiátrịcủanólàđịachỉcuảmộtvùngnhớứngvớimộtbiếnkiểuT, hoặclàgiátrịNULL.
Contrỏ–Khaibáo • CúphápđịnhnghĩamộtkiểucontrỏtrongngônngữC : typedef<kiểucơsở> * < kiểucontrỏ>; • Vídụ : typedefint *intpointer; intpointerp; hoặc int *p; lànhữngkhaibáohợplệ.
Contrỏ–Thaotáccănbản • Cácthaotáccơbảntrênkiểucontrỏ:(minhhọabằngC) • Khi 1 biếncontrỏplưuđịachỉcủađốitượngx, tanói‘ptrỏđếnx’. • Gánđịachỉcủamộtvùngnhớcontrỏp: p = <địachỉ>; ví duï : int i,*p; p=&i; • Truyxuấtnộidungcủađốitượngdoptrỏđến (*p)
Danhsáchliênkết (List) • Địnhnghĩa: Moät danh saùch (list) laø moät taäp hôïp goàm moät soá höõu haïn phaàn töû cuøng kieåu, coù thöù töï. Coù hai caùch caøi ñaët danh saùch laø : • Caøi ñaët theo kieåu keá tieáp : ta coù danh saùch keà hay danh saùch ñaëc. • Caøi ñaët theo kieåu lieân keát : ta coù danh saùch lieân keát.
Danhsáchliênkết (List) • Danh saùch keà : • Caùc phaàn töû cuûa danh saùch goïi laø caùc node, ñöôïc löu tröõ keà lieàn nhau trong boä nhôù. Moãi node coù theå laø moät giaù trò kieåu int, float, char, … hoaëc coù theå laø moät struct vôùi nhieàu vuøng tin. Maûng hay chuoãi laø daïng cuûa danh saùch keà. • Ñòa chæ cuûa moãi node trong danh saùch ñöôïc xaùc ñònh baèng chæ soá (index). Chæ soá cuûa danh saùch laø moät soá nguyeân vaø ñöôïc ñaùnh töø 0 ñeán moät giaù trò toái ña naøo ñoù. • Danh saùch keà laø caáu truùc döõ lieäu tónh, soá node toái ña cuûa danh saùch keà coá ñònh sau khi caáp phaùt neân soá node caàn duøng coù khi thöøa hay thieáu. Ngoaøi ra danh saùch keà khoâng phuø hôïp vôùi caùc thao taùc thöôøng xuyeân nhö theâm hay xoùa phaàn töû treân danh saùch,
Danhsáchliênkết (List) • Danh saùch lieân keát : • Caùc phaàn töû cuûa danh saùch goïi laø node, naèm raûi raùc trong boä nhôù. Moãi node, ngoaøi vuøng döõ lieäu thoâng thöôøng, coøn coù vuøng lieân keát chöùa ñòc chæ cuûa node keá tieáp hay node tröôùc noù. • Danh saùch lieân keát laø caáu truùc döõ lieäu ñoäng, coù theå theâm hay huûy node cuûa danh saùch trong khi chay chöông trình. Vôùi caùch caøi ñaët caùc thao taùc theâm hay huûy node ta chæ caàn thay ñoåi laïi vuøng lieân keát cho phuø hôïp. • Tuy nhieân, vieäc löu tröõ danh saùch lieân keát toán boä nhôù hôn anh saùch keà vì moãi node cuûa danh saùch phaûi chöùa theâm vuøng lieân keát. Ngoaøi ra vieäc truy xuaát node thöù I trong danh saùch lieân keát chaäm hôn vì phaûi duyeät töø ñaàu danh saùch.
Danhsáchliênkết (List) • Cónhiềukiểutổchứcliênkếtgiữacácphầntửtrongdanhsáchnhư : • Danhsáchliênkếtđơn • Danhsáchliênkếtkép • Danhsáchliênkếtvòng • …
A B X Z Y D A B C Danhsáchliênkết (List) • Danhsáchliênkếtđơn:mỗiphầntửliênkếtvớiphầntửđứngsaunótrongdanhsách: • Danhsáchliênkếtkép:mỗiphầntửliênkếtvớicácphầntửđứngtrướcvàsaunótrongdanhsách:
A B C A B X Z Y D Danhsáchliênkết (List) • Danhsáchliênkếtvòng :phầntửcuốidanhsáchliênkếtvớiphầntửđầudanhsách:
DSLK - định nghĩa • DSLK đơn là chuỗi các node, được tổ chức theo thứ tự tuyến tính • Mỗi node gồm 2 phần: • Phần Data, information : löu tröõ caùc thoâng tin veà baûn thaân phaàn töû . • Phần link hay con trỏ : löu tröõ ñòa chæ cuûa phaàn töû keá tieáp trong danh saùch, hoaëc löu tröõ giaù trò NULL neáu laø phaàn töû cuoái danh saùch. Data Link Node
Cấu trúc dữ liệu của DSLK đơn typedefstructNode { int data; // Data là kiểu đã định nghĩa trước Node * link; //con trỏ chỉ đến cấu trúc NODE };
Joe Bill 140 500 Marta NULL Sahra 140 Kock 230 Lưu trữ DSLK đơn trong RAM Địa chỉ 000 • Ví dụ :Ta có danh sách theo dạng bảng sau 100 110 140 230 500 …
DSLK đơn truy xuất – Minh họa Địa chỉ • VD: 140 first 100 100 ‘Joe’ 140 ‘Marta’ 110 500 110 ‘Koch’ 230 ‘Bill’ 500 230 ‘Bill’ NULL
A B X Z Y last first Tổchức, quảnlý • Đểquảnlýmộtxâuđơnchỉcầnbiếtđịachỉphầntửđầuxâu. • ContrỏFirstsẽđượcdùngđểlưutrữđịachỉphầntửđầuxâu, tagọiFirstlàđầuxâu. Tacókhaibáo : NODE* first; • Đểtiệnlợi, cóthểsửdụngthêmmộtcontrỏlastgiữđịachỉphầntửcuốixâu. Khaibáolastnhưsau : NODE* last;
DSLK – Khai báo phần Data typedef struct node { DataType data; struct node * link; }NODE; Cấu trúc node DataType ? typedef struct node { int data; struct node * link; }NODE; typedef struct node { SinhVien data; struct node * link; }NODE;
Tổchức, quảnlý Khaibáokiểucủa 1 phầntửvàkiểudanhsáchliênkếtđơn và để đơn giản ta xét mỗi node gồm vùng chứa dữ liệu là kiểu số nguyên : // kiểucủamộtphầntửtrongdanhsách typedefstructNode { int data; NODE * link; }NODE; typedefstructList // kiểudanhsáchliênkết { NODE* first; NODE* last; }LIST; Trong thực tế biến data là một kiểu struct
Tạomộtphầntử • ThủtụcGetNodeđểtạoramộtphầntửchodanhsáchvớithôngtinchứatrongx NODE* GetNode(int x) { NODE *p; // Cấpphátvùngnhớchophầntử p = (NODE*)malloc(sizeof(NODE))//p= new NODE; if (p==NULL) { cout<<“Khong du bo nho!”; exit(1); } p->data = x; // Gánthôngtinchophầntửp p->link = NULL; return p; }
Tạomộtphầntử Đểtạomộtphầntửmớichodanhsách, cầnthựchiệncâulệnh: new_ele = GetNode(x); new_elesẽquảnlýđịachỉcủaphầntửmớiđượctạo.
Cácthaotáccơsở • Tạodanhsáchrỗng • Thêmmộtphầntửvàodanhsách • Tìmkiếmmộtgiátrịtrêndanhsách • Tríchmộtphầntửrakhỏidanhsách • Duyệtdanhsách • Hủytoànbộdanhsách
Khởitạodanhsáchrỗng last voidInit(LIST &l) { l.first = l.last = NULL; } first
Thêmmộtphầntử Có 3 vị trí thêm phần tử mới vào danh sách : • Thêmvàođầudanhsách • Nốivàocuốidanhsách • Chènvàodanhsáchsaumộtphầntửq
X Thêmmộtphầntử last first new_ele
X A Thêmmộtphầntửvàođầu last first B C D E new_ele
Thêmmộtphầntửvàođầu //input: danh sách (first, last), phần tử mới new_ele //output: danh sách (first, last) với new_ele ở đầu DS • Nếu Danh sách rỗng Thì • first = new_ele; • last = first; • Ngược lại • new_ele ->link = first; • first = new_ele ;
Thêmmộtphầntửvàođầu voidAddFirst(LIST &l, NODE* new_ele) { if (l.first == NULL) //Xâurỗng { l.first = new_ele; l.last = l.first; } else { new_ele->link = l.first; l.first = new_ele; } }
Thêmmộtthànhphầndữliệuvàođầu //input: danhsách (first, last), thànhphầndữliệuX //output: danhsách (first, last) vớiphầntửchứaXởđầuDS • Tạophầntửmớinew_eleđểchứadữliệuX • Nếutạođược: Thêmnew_elevàođầudanhsách • Ngượclại Báolỗi
Thêmmộtthànhphầndữliệuvàođầu NODE* Insertfirst(LIST &l, int x) { NODE* new_ele = GetNode(x); if (new_ele == NULL) returnNULL; AddFirst(l, new_ele); return new_ele; }
Tạo Link list bằng cách thêm vào đầu voidcreate_list_first(LIST &l, int x) { NODE *p; int n; cout<<“Nhap so phan tu:”; cin>>n; for (int i=1;i<=n;i++) // nen dung vong lap do while de viet { //Insertfirst(l,x); p=GetNode(x); AddFirst(l,p); } }
X A Thêmmộtphầntửvàocuối last first B C D E new_ele
Thêmmộtphầntửvàocuối //input: danhsách (first, last), phầntửmớinew_ele //output: danhsách (first, last) vớinew_eleởcuốiDS • Nếu Danh sách rỗng Thì • first = new_ele; • last = first; • Ngược lại • last->link = new_ele ; • last = new_ele ;
Thêmmộtphầntửvàocuối voidInsertLast(LIST &l, NODE *new_ele) { if (l.first==NULL) { l.first = new_ele; l.last = l.first; } else { l.last->link = new_ele; l.last = new_ele ; } }
Thêmmộtthànhphầndữliệuvàocuối //input: danhsách (first, last), thànhphầndữliệuX //output: danhsách (first, last) vớiphầntửchứaXởcuốiDS • Tạophầntửmớinew_eleđểchứadữliệuX • Nếutạođược: Thêmnew_elevàocuốidanhsách • Ngượclại Báolỗi
Thêmmộtthànhphầndữliệuvàocuối NODE* InputLast(LIST &l) { int x,n; printf(“Nhap so phan tu :”); scanf(“%d”,&n); for(int i=0;i<n;i++) { printf(“Nhap phan tu thu %d :”,i); scanf(“%d”,&x); NODE* p=GetNode(x); InsertLast(l, new_ele); } }
Tạo Link list bằng cách thêm vào cuối voidcreate_list_last(list &l, int x) { node *p; int n; cout<<“Nhap so phan tu:”; cin>>n; for (int i=1;i<=n;i++) // nen dung vong lap do while de viet { p=GetNode(x); InsertLast(l,p); } }