Bài tập cấu trúc dữ liệu và giải thuật có lời giải

26 1.1K 5
Bài tập cấu trúc dữ liệu và giải thuật có lời giải

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

ĐỀ CƯƠNG ƠN TẬP MƠN CTDL & TT CĨ LỜI GIẢI PHẦN I LÝ THUYẾT CHƯƠNG I 1.1 Các khái niệm bản - Mô hình dữ liệu : là mô hình toán học cùng với các phép toán có thể thực hiện các đối tượng của mô hình - Kiểu dữ liệu trừu tượng : là một mô hình dữ liệu được xét cùng với một số xác định các phép toán - Giải thuật : là một dãy các câu lệnh chặt chẽ và rõ ràng, xác định một dãy các thao tác một số đối tượng nào đó cho sau một số hữu hạn bước thực hiện ta đạt được kết mong muốn - Cấu trúc dữ liệu : Cách thức tổ chức biểu diễn dữ liệu mà theo đó dữ liệu được lưu trữ và được xử lý MTĐT, được gọi là cấu trúc dữ liệu - Kiểu dữ liệu : + Mỗi kiểu DL ngôn ngữ lập trình thường đại diện cho một loại dữ liệu thực tế + Trong ngôn ngữ lập trình, một kiểu dữ liệu T được xác định bởi một bộ đó : V : tập các giá trị hợp lệ mà một đối tượng kiểu T có thể lưu trữ O : tập các thao tác xử lý có thể thi hành đối tượng kiểu T - Mối quan hệ giữa CTDL và GT : Giải thuật tác động dữ liệu lưu trữ các cấu trúc để cho kết mong muốn Trong lập trình, chúng quan hệ với theo ràng buộc sau: Giải thuật + cấu trúc dữ liệu = chương trình 1.2 Phân biệt CTLT và CTLT ngoài - CTLT : được lưu trữ bộ nhớ Ví dụ: mảng, ghi… - CTLT ngoài : được lưu trữ bộ nhớ ngoài Ví dụ: tệp tin, bảng… 1.3 Đệ quy - Khái niệm : Một đối tượng được gọi là đệ quy nó bao gồm chính nó là một bộ phận nó được định nghĩa dưới dạng của chính nó - Giải thuật đệ quy : là giải thuật có chứa lời giải đệ quy Lời giải đệ quy là lời giải của bài toán T được thực hiện bởi lời giải của bài toán T’ có dạng T (cỡ của T’< T) - Đặc điểm của giải thuật đệ quy : Có đặc điểm - Trong giải thuật đệ quy bao giờ có lời gọi đến chính nó - Sau mỗi lời gọi đệ quy, kích thước của bài toán được thu nhỏ trước - Có một trường hợp suy biến: bài toán được giải theo một cách khác hẳn và giải thuật kết thúc - Ưu – nhược điểm của GT đệ quy : + ưu điểm : thuận lợi cho việc biểu diễn bài toán, đồng thời làm gọn chương trình + nhược điểm : không tối ưu mặt thời gian (so với sử dụng vòng lặp), gây tốn bộ nhớ - Viết thuật toán tính n!, tính dãy fibonaci + Tính n! int TinhGT (int n) { if(n==0) return 1; else return (n*TinhGT(n-1)); } + Tính fibonaci int TinhFB (int n) { if(n==1 || n==2) return 1; else return (TinhFB(n-1)+TinhFB(n-2)); } 1.4 Sự cần thiết phân tích giải thuật - Một bài toán có thể có nhiều giải thuật khác Phân tích giải thuật đánh giá các giải thuật và tìm giải thuật tốt Các tiêu chuẩn đánh giá: + Giải thuật đắn: để kiểm tra tính đắn của giải thuật ta có thể cài đặt giải thuật đó và cho thực hiện máy với một số bộ dữ liệu mẫu lấy kết thu đc so sánh với kết biết + Giải thuật đơn giản: cần giải thuật dễ viết chương trình để nhanh chóng có được kết + Độ phức tạp của giải thuật : là hiệu của giải thuật Tính hiệu thể hiện qua mặt là thời gian và không gian 1.5 Các bước bản từ bài toán đến chương trình - Bước 1: Thiết kế: nhằm xác định bài toán cần giải và xây dựng mô hình toán học cho bài toán - Bước 2: Mã hoá: Sử dụng ngôn ngữ lập trình cụ thể để viết chương trình ứng với cách làm của giai đoạn trc nó CHƯƠNG II 2.1 Các khái niệm bản - Danh sách + Khái niệm : Danh sách là một cấu trúc dùng để lưu trữ một tập hợp hữu hạn biến động các phần tử thuộc cùng một lớp đối tượng nào đó Có thể cài đặt danh sách bởi mảng và bởi trỏ, tương ứng ta có danh sách và danh sách móc nối (danh sách liên kết) + Hình ảnh : + Nguyên tắc hoạt động : + Ví dụ : - Ngăn xếp + Khái niệm : ngăn xếp là một danh sách tuyến tính đó phép bổ sung một phần tử vào ngăn xếp và phép loại bỏ một phần tử khỏi ngăn xếp được thực hiện ở một đầu, đầu đó gọi là đỉnh của ngăn xếp + Hình ảnh : + Nguyên tắc hoạt động : + Ví dụ : - Hàng đợi + Khái niệm : hàng đợi là một danh sách tuyến tính đó phép bổ sung một phần tử vào hàng đợi được thực hiện ở một đầu phép loại bỏ mợt phần tử khỏi hàng đợi được thực hiện ở đầu + Hình ảnh : + Nguyên tắc hoạt động : + Ví dụ : 2.3 Phân biệt ngăn xếp và hàng đợi - Việc thêm vào, lấy một phần tử từ ngăn xếp được thực hiện ở một đầu, đó ngăn xếp hoạt động theo nguyên tắc LIFO, thích hợp với các ứng dụng có trình tự truy xuất ngược với trình tự lưu trữ - Việc thêm vào, lấy một phần tử từ hàng đợi được thực hiện ở hai đầu khác nhau, đó hàng đợi hoạt động theo nguyên tắc FIFO, thích hợp với các ứng dụng có trình tự truy xuất và trình tự lưu trữ 2.2 Phân biệt mảng và danh sách liên kết Mảng Vùng nhớ của các phần tử mảng được sắp xếp liên tục Truy cập tới phần tử mảng là truy cập trực tiếp dựa vào số (ví dụ: a[0], a[1], a[2],…, a[n])  Kích thước của mảng là hằng số, không thay đổi chạy chương trình  Sử dụng mảng không tối ưu được bộ nhớ Có thể thừa thiếu bộ nhớ xóa chèn phần tử vào mảng Danh sách liên kết Vùng nhớ của các phần tử danh sách liên kết được sắp xếp tùy ý (do hệ điều hành) Các phần tử lưu trỏ trỏ tới phần tử Cần phải duyệt tuần tự muốn truy cập tới phần tử danh sách liên kết   Kích thước của danh sách liên kết có thể thay đổi chạy chương trình Sử dụng danh sách liên kết tối ưu được bộ nhớ Vùng nhớ được cấp phát thêm cần chèn thêm phần tử mới, vùng nhớ được free xóa phần tử CHƯƠNG III 3.1 Các khái niệm bản - Cây tổng quát : là một tập hợp T các phần tử (gọi là nút của cây) đó có nút đặc biệt được gọi là gớc, các nút lại được chia thành những tập rời T1, T2 , , Tn theo quan hệ phân cấp đó Ti là một Mỗi nút ở cấp i quản lý một số nút ở cấp i+1 Quan hệ này người ta gọi là quan hệ cha-con - Cây nhị phân : là một cây, đó số mỗi đỉnh tối đa là và được sắp thành trái và phải - Cây tìm kiếm nhị phân : là nhị phân t/m các đk: + All khoá các đỉnh của bên trái có giá trị trước nhỏ các khoá đỉnh gốc + Khoá gốc trc nhỏ all các khoá ở các đỉnh của bên phải + Cây bên trái và bên phải là TKNP - Các dạng nhị phân đặc biệt : + Cây lệch trái + Cây lệch trái + Cây zic-zắc + Cây nhị phân hoàn chỉnh + Cây nhị phân đầy đủ 3.2 Các nguyên tắc duyệt đa phân và nhị phân - Nguyên tắc duyệt đa phân (cây tổng quát, cây) + Duyệt theo thứ tự trước Nếu T rỗng: Không làm gì Nếu T khác rỗng: Trình tự thăm các sau: Thăm gốc T Thăm các T1, T2,…., T(k) của T theo thứ tự trước + Duyệt theo thứ tự giữa Nếu T rỗng: Không làm gì Nếu T khác rỗng: Trình tự thăm: Thăm T1 của T theo thứ tự giữa Thăm gớc T Thăm các lại của T theo thứ tự giữa T2,….,T(k) + Duyệt theo thứ tự sau Nếu T rỗng: Không làm gì Nếu T khác rỗng: Trình tự thăm: Thăm các T1, T2,…,T(k) của T theo thứ tự sau Thăm gốc T - Nguyên tắc duyệt nhị phân + Duyệt tiền tự – thứ tự trước: duyệt nút gốc, duyệt tiền tự trái duyệt tiền tự phải + Duyệt trung tự – duyệt theo thứ tự giữa: duyệt trung tự trái đến nút gốc sau đó là duyệt trung tự phải + Duyệt hậu tự – duyệt theo thứ tự sau: Duyệt hậu tự trái duyệt hậu tự phải sau đó là nút gốc CHƯƠNG IV 4.1 Định nghĩa đồ thị - Đồ thị là một cấu trúc rời rạc dùng để mô tả một tập hợp các đối tượng rời rạc có mối quan hệ n-m với (n,m>0) Ký hiệu đồ thị G là G=, đó: + V là tập các đỉnh + E là tập các cạnh/cung 4.2 Các khái niệm - Đồ thị có hướng : E là tập các cặp (u,v) khác (v,u), gọi là các cung - Đồ thị vô hướng : E gồm các cặp (u,v) = (v, u), gọi là các cạnh - Đồ thị liên thông : có đường giữa mọi cặp đỉnh phân biệt của đồ thị - Đồ thị đơn : giữa hai đỉnh u, v bất kỳ có nhiều cạnh/cung - Đồ thị đa : giữa hai đỉnh u, v bất kỳ có thể có nhiều cạnh/cung - Đỉnh kề : e = (u, v) là một cạnh thuộc E thì ta nói u, v kề nhau, và e là liên thuộc với u và v - Đường : một đường P = (V1, V2, …., Vp) mà cạnh (V(i-1), V(i)) thuộc E, với i = 2… p; - Chu trình : P được gọi là chu trình V1 = Vp - Bậc của một đỉnh đồ thị : bậc của v (ký hiệu: deg(v)) là số cạnh liên thuộc với v CHƯƠNG V 5.1 Tập hợp - Định nghĩa tập hợp : Tập hợp là một cấu trúc rời rạc được nói là chứa các phần tử của nó Tập hợp thường dùng để gom nhóm các phần tử có các tính chất chung lại với nhau, nó có thể chứa các phần tử chẳng có mối quan hệ gì với - Các phương pháp mô tả tập hợp : có cách mô tả tập hợp + Cách 1: Dùng biểu đồ Ven là một đường cong khép kín, các điểm đường cong đó các phần tử của tập hợp + Cách 2: Liệt kê tất các phần tử của tập hợp A Ví dụ: A = {1, 2, 3}… + Cách 3: Nêu lên các đặc trưng cho biết chính xác một đối tượng bất kỳ có là một phần tử của tập A hay không Ví dụ : A = {x | x là số nguyên chẵn} 5.2 Hàm băm - Tư tưởng hàm băm : + Phân chia tập hợp cho thành một số cố định các lớp(giả sử N lớp được đánh số từ -> N-1) + Sử dụng một mảng T có số chạy từ đến N-1 để chứa các phần tử tập hợp, mỗi thành phần T[i] là một “rổ” đựng các phần tử thuộc lớp thứ i, các phần tư mỗi lớp được tổ chức thành một danh sách liên kết, T[i] là trỏ trỏ tới phần tử đầu tiên lớp thứ i T chính là bảng băm mở - Tác dụng hàm băm : Phân chia các phần tử của tập hợp vào các lớp Nếu x là giá trị khóa của môt phần tử nào đó của tập hợp thì h(x) là số nào đó của mảng T, h(x) được gọi là giá trị băm của x, ta nói x thuộc lớp h(x); - Tiêu chí lựa chọn : + Hàm băm phải cho phép tính được dễ dàng và nhanh chóng giá trị băm của mỗi khóa + Phân bố các khóa vào các lớp PHẦN II BÀI TẬP I Bài tập về danh sách, ngăn xếp, hàng đợi Danh sách  Dạng cài đặt Theo mảng #define N 100 Typedef int item; typedef struct { item Elems[N]; int size; }List; Theo tro Typedef int item; typedef struct Node { item Data; Node *next; }; typedef Node *List;  Danh sách kế tiếp #include #include #define N 100; typedef int item; //Cai dat cau truc mang typedef struct { item Elems[N]; int size; } List; //Ham khoi tao danh sach rong void Init(List *L) { (*L).size = 0; //size = } //Ham kiem tra danh sach day int Isfull (List L) { return (L.size==N); } //Ham kiem tra danh sach rong int Isempty (List L) { return (L.size==0); } //Ham khoi tao gia tri x item init_x() { int x; scanf("%d", &x); return x; } //Ham nhap du lieu void Input (List *L) { int n; printf("Nhap so phan tu cua danh sach: "); scanf("%d", &(*L).size); int i; for (i=0; inext; Q->next = P; } } } //Them phan tu o vi tri cuoi //Xoa phan tu o vi tri dau void Del_frist (List &L, item &x) { x = L->Data; L = L->next; } //Xoa phan tu o vi tri thu k void Del_k (List &L, item &x, int k) { Node *P=L; int i=1; if (klen(L)) printf("Vi tri xoa khong hop le !"); else { if (k==1) Del_frist(L,x); else //xoa vi tri k != { while (P != NULL && i != k-1) { P=P->next; i++; } P->next = P->next->next; } } } //Xoa phan tu o vi tri cuoi //Nhap du lieu cho danh sach void Input (List &L) { int i=0; item x; { i++; printf ("Nhap phan tu thu %d : ",i); scanf("%d",&x); if (x != 0) Insert_k(L,x,len(L)+1); } while(x != 0); } //Hien thi du lieu void Output (List L) { Node *P=L; while (P != NULL) { printf("%5d",P->Data); P = P->next; } printf("\n"); } Ngăn xếp  Dạng cài đặt Theo mảng #define Max 100 Typedef int item; struct Stack { int Top; item Data[Max]; }; Theo trỏ typedef int item; struct Node { item Data; Node *Next; }; typedef struct Stack { Node *Top; };  Các thao tác dùng tro //tao cau truc stack typedef int item; struct Node { item Data; Node* Next; }; typedef struct stack { Node* Top; }; //khoi tao ngan xep rong void Init(stack &s) { s.Top=NULL; } //kiem tra danh sach rong int empty (stack s) { return(s.Top==NULL); } //tao mot node Node* MakeNode(item x) { Node*p = (Node*) malloc(sizeof(Node)); p->Next = NULL; p->Data = x; return p; } //them phan tu vao dinh void Push(stack &s, item x) { Node*p = MakeNode(x); p->Next = s.Top; s.Top = p; } //Xoa phan tu o dinh int Pop(stack &s) { if(!empty(s)) { item x=s.Top->Data; s.Top=s.Top->Next; return x; } } //Nhap du lieu void Input(stack &s) { int i=0; item x; { i++; printf("\nNhap phan tu thu %d ", i+1); scanf("%d", &x); if(x!=0) Push(s,x); }while(x!=0); } //Hien thi du lieu void Output(stack s) { Node *p = s.Top; while (p!=NULL) { printf("%d ", p->Data); p=p->Next; } printf("\n"); } //Chuyen tu he 10 sang he void Dec_to_Bin() { int n,x; stack s; Init(s); printf("\n nhap he so 10: "); scanf("%d",&n); while (n>=1) { x=n%2; Push(s,x); printf("%d",x); n/=2; } printf("\n"); } Hàng đợi  Dạng cài đặt Theo mảng define MAX 100; typedef int item; struct Queue { int front, rear; item data[MAX]; int count; }; Theo trỏ typedef int item; struct Queue struct Node { { Node * Front, *Rear; item Data; int count; Node * Next; }; };  Các thao tác dùng tro //Cai dat node struct Node { item Data; Node * Next; }; //Cai dat queue struct Queue { Node * Front, *Rear; int count; }; //Khoi tao queue rong void Init(Queue &Q) { Q.Front = Q.Rear = NULL; Q.count = 0; } //Kiem tra queue rong int Isempty (Queue Q) { if (Q.count == 0) return 1; return 0; } //Tao mot node Node *MakeNode(item x) { Node *P = (Node*) malloc(sizeof(Node)); P->Next = NULL; P->Data = x; return P; } //Them phan tu vao cuoi queue void Push(Queue &Q, item x) { Node *P = MakeNode(x); if (Isempty(Q)) { Q.Front = Q.Rear = P; } else { Q.Rear->Next = P; Q.Rear = P; } Q.count ++ ; } //Xoa phan tu o dau queue int Pop(Queue &Q) { if (Isempty(Q)) { printf("Hang doi rong !"); return 0; } else { item x = Q.Front->Data; if (Q.count == 1) //neu co phan tu Init(Q); else Q.Front = Q.Front->Next; Q.count ; return x; } } //Them phan tu x o vi tri thu k //Xoa phan tu x o vi tri thu k //Nhap queue void Input (Queue &Q) { int i=0; item x; { i++; printf ("Nhap phan tu thu %d : ",i); scanf("%d",&x); if (x != 0) Push(Q,x); } while(x != 0); } //Hien thi queue void Output(Queue Q) { Node *P = Q.Front; while (P != NULL) { printf("%d ",P->Data); P = P->Next; } printf("\n"); } II Bài tập về cây, đồ thị, tập hợp Cây  Tự vẽ gồm 10-12 đỉnh Duyệt vừa vẽ theo các thứ tự: trước, giữa, sau  Vẽ nhị phân biểu diễn biểu thức toán học, đưa biểu thức toán học về dạng tiền tố, hậu tố  Dạng cài đặt đa phân bằng trưởng và em liền kề Theo mảng #define N 100; typedef int item; struct Node { item infor; int EldestChild; int NextSibling; }; typedef struct Tree { Node Elems[N]; }; Tree T Theo trỏ struct Node { item infor; struct Node *EldestChild; struct Node *Nextsibling; }; typedef struct Node *Tree; Tree root;  Dạng cài đặt nhị phân Theo mảng #define N 100; typedef int item; struct Node { item infor; int left; int right; }; typedef struct BTree { Node Elems[N]; }; BTree T; Theo trỏ typedef int item; typedef struct Node { item data; Node *left, *right; } Node; Node *BTree;  Dạng cài đặt TKNP bằng tro typedef struct Node { int key; int data; Node *left, *right; } Node; typedef Node *SearchTree;  Trình bày ý tưởng và viết các hàm cho đa phân Tìm trưởng, em kề  Ý tưởng  Cài đặt Tìm cha của đỉnh k  Ý tưởng: Duyệt lần lượt các đỉnh cây, xuất phát từ gốc (i=1), kiểm tra xem trưởng j của i có = k hay không? - Nếu bằng thì i chính là cha cần tìm - Ngược lại, kiểm tra em liền kề của trưởng j xem có bằng k hay ko? + Nếu bằng thì i chính là cha cần tìm + Nếu không ktra j là em liền kề của j cũ Cứ tiếp tục vậy kiểm tra hết các của i mà không có nào = k thì duyệt đỉnh i Ngược lại cần j của i = k thì dừng tìm kiếm và kl i chính là đỉnh cha cần tìm  Cài đặt: int Parent (Tree T, int k) { int i=0; int j; int found=0; while(ikey == x) { Node *P = T; return P; } if (T->key > x) return searchKey(T->Left, x); if (T->key < x) return searchKey(T->Right, x); } return NULL; } Thêm đỉnh có khoá x vào int insertNode (Tree &T, item x) { if (T != NULL) { if (T->key == x) return -1; if (T->key > x) return insertNode(T->Left, x); else if (T->key < x) return insertNode(T->Right, x); } T = (Node *) malloc(sizeof(Node)); if (T == NULL) return 0; T->key = x; T->Left = T->Right = NULL; return 1; } Xoá đỉnh có khoá x  Ý tưởng: Gọi X là nút cần hủy, có ba trường hợp: TH1: X là nút lá => đơn giản cần hủy X vì nó không móc nối đến phần tử nào khác TH2: X có (trái phải): Trước hủy X ta móc nối cha của X với của nó TH3: X có đủ con: ta không thể hủy trực tiếp X có đủ Ta hủy gián tiếp Thay vì hủy X, ta tìm một phần tử mạng Q Phần tử này có tối đa một Thông tin lưu Q được chuyển lên lưu X Sau đó, nút bị hủy thật sự là Y giống trường hợp đầu Vấn đề là phải chọn Y cho lưu Q vào vị trí của X, vẫn là CNPTK Có phần tử thỏa mãn yêu cầu: + Phần tử nhỏ (trái nhất) phải + Phần tử lớn (phải nhất) trái  Cài đặt: int delKey(Tree &T, item x) { if (T==NULL) return 0; else if (T->key > x) return delKey(T->Left, x); else if (T->key < x) return delKey(T->Right, x); else { Node *P = T; if (T->Left == NULL) T = T->Right; else if (T->Right == NULL) T = T->Left; else { Node *S = T, *Q = S->Left; while (Q->Right != NULL) { S = Q; Q = Q->Right; } P->key = Q->key; S->Right = Q->Left; delete Q; } } return 1; } Đồ thị  Viết dạng cài đặt đồ thị Theo ma trận kề #define MAX 100 struct DoThi { int n; int a[MAX][MAX]; }; Theo danh sách kề struct Cell { int vertex; Cell *next; }; const int N=100; typedef Cell *Graph[N];  Trình bày ý tưởng và viết các hàm Nhập dữ liệu void NhapMTKe(int A[][MaxV], int &V) { printf("Nhap V:"); scanf("%d", &V); for (int i=0; i<V; i++) { for (int j=0; j<V; j++) { printf("A[%d,%d] = ", i+1, j+1); scanf("%d", &(A[i][j])); } } } Hiển thị dữ liệu void HienThiMTKe(int A[][MaxV], int V) { printf("\nMa tran ke:\n"); for (int i=0; i<V; i++) { for (int j=0; j<V; j++) printf("%3d ", A[i][j]); printf("\n"); } } Xác định bậc của đỉnh k đồ thị int Deg(int i) { int deg=0; for(int j=0;j

Ngày đăng: 05/12/2018, 09:18

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan