KTLT C2 LinearDynamicStructures
KTLT C2 LinearDynamicStructures
Chapter 02
medium.com/@mklynn100/data-structures-and-algorithms-94cdb0e18d17
5
medium.com/@mklynn100/data-structures-and-algorithms-94cdb0e18d17
6
7
DYNAMIC ARRAY
www.nextptr.com/
12
medium.com/@mklynn100/data-structures-and-algorithms-94cdb0e18d17
13
medium.com/@mklynn100/data-structures-and-algorithms-94cdb0e18d17
14
• General syntax:
array_name [indexExp]
// or: *(array_name + indexExp)
where indexExp, called an index, is any expression whose value is
a non-negative integer.
• Index value specifies the position of component in array, it
always starts at zero (0).
• Examples:
int k=3, *a =new int [ 2*k+1 ];
*a = 2021; // a[0]=2021
*(a+1) = *(a+2) = 4; // a[1]=a[2]=4
cout<< a[0] << a[1] << a[2]; // output: 202144
17
Example:
// Static Array // Dynamic Array
int a[3] = {21, 4}; int *a = new int [3] {21, 4};
cout<<a[0]<<a[1]<<a[2]; //out: 2140 // or: int * a { new int [3] {21, 4} };
int b[5] = { }; cout<<a[0]<<a[1]<<a[2]; //out: 2140
cout<<b[0]<<b[1]<<b[2]; // out: 000 int *b = new int [5] { }; // int*b {new int [5] { }};
cout<<b[0]<<b[1]<<b[2]; // out: 000
18
Input Output
void input2dArr(Array2D A) { void output2dArr(Array2D A)
for (int i=0; i<A.rows; i++) { {
for (int j=0; j<A.cols; j++) { for (int i=0; i<A.rows; i++)
cout<< “ a [ "<< i << “ ] [ “ << j << “ ]= "; {
cin>> A.a [ i ] [ j ] ; for (int j=0; j<A.cols; j++)
} cout<<A.a [ i ] [ j ] << “ “;
cout << endl ; cout << endl ;
} }
} }
35
int **createMatrix(int M, int N) { void createlMatrix(Array2D &A, int Rows, int Cols) {
int **a = new int* [M]; A.rows = Rows; A.cols = Cols;
for (int i=0 ; i < M ; i++) A.a = new int *[A.rows];
a [ i ] = new int[N]; for (int i=0; i < A.rows; i++)
return a;
A.a[i]= new int [A.cols];
}
}
void fillMatrix(int** a, int M, int N) {
void fillMatrix (Array2D A) {
for (int i=0 ; i < M; i++)
for (int i=0; i<A.rows; i++)
for(int j=0 ; j < N ; j++)
for (int j=0; j<A.cols; j++)
a [ i ][ j ] = (i+1)*1000 + j+1;
}
A.a[ i ] [ j ] = (i+1)*1000 + j+1;
}
void printMatrix(int** a, int M, int N) {
void printMatrix (Array2D A) {
for (int i=0 ; i < M ; i++) {
for (int i=0; i<A.rows; i++) {
for (int j=0; j<N; j++) cout<<a[ i ][ j ]<<" ";
for (int j=0; j<A.cols; j++) cout<<A.a[ i ] [j]<<“ “;
cout<<endl;
}
cout << endl ;
}
}
}
void main() {
void main() {
int R=3, C=4, **Arr = createMatrix(R, C);
Array2D Arr;
fillMatrix (Arr, R, C);
createMatrix (Arr, 3, 4);
printMatrix (Arr, R, C);
fillMatrix (Arr);
// freeMatrix (Arr, R);
}
printMatrix (Arr); // freeMatrix (Arr);
}
37
• The first node is usually called pHead, & the last => pTail
40
• In terms of circle: A B C
pHead
▪ Circularly-LL : the last pointer points to the first node, all nodes are
linked in a continuous circle, without using NULL.
A B C D E
pHead
pTail
A B C D E
pHead
struct tagNode { // Singly LL Node
Type data;
struct tagNode * pNext;
} NODE;
struct SLList{ // Singly LL Type
NODE * pHead, * pTail;
};
SLList List; // Singly LL Declaration
List.pHead = List.pTail = NULL; //Initialize Empty List
46
A B C D
A B C D E
A B C D
• Addition
• Prepend
• Append
• After a node
• Before a node
• Deletion
• First node
• After a node
• All node
52
A B C D E
pHead
53
pTail
A B C D E
pHead
54
X
pTail
A B C D E
pHead
55
• If <q> is the first node of SLL (q==Head): see the first case
• Else: find previous node <p> and use the previous case
p = pHead;
while (p->pNext != q) //find previous node of <q>
p = p->pNext;
p->pNext = newNode;
newNode->pNext = q; q
X
pTail
A B C D E
pHead
p
56
pTail
A B C D E
pHead
p = pHead
57
pTail
A B C D E
pHead
p = q->pNext
58
// Singly Linked List Example @THV.2020.05 NODE* updateNode(SLList &L) { // return NULL if not found
// ----------------------------------------- cout<<"Enter the key of node: ";
#include <iostream> int key; cin>>key;
using namespace std; NODE * p = searchNode(L, key);
struct Element { // struct of Element if (p == NULL) return NULL;
int key; cout<<"Enter the new key of node: ";
float xyz; // and_or sth else cin>> p->data.key;
}; cout<<"Enter the new <xyz> of node: ";
typedef struct tagNode { // Singly LL Node cin>> p->xyz;
Element data; return p;
struct tagNode * pNext; }
} NODE; NODE* prependNode(SLList &L, Element X) {// return newNode
typedef struct tagList { // Singly LL Type NODE* newNode = new NODE {X, NULL};
NODE * pHead, * pTail; if (newNode==NULL) return NULL;
} SLList; if (L.pHead==NULL) // SLL is empty
L.pHead = L.pTail = newNode;
void printList(const SLList L) { else {
NODE * current = L.pHead; newNode->pNext = L.pHead;
cout<<"-------------------"<<endl<<" Elements of List: [ "; L.pHead = newNode;
while (current != NULL) { }
cout<< current->data.key <<" "; return newNode;
current = current->pNext; }
} NODE* appendNode(SLList &L, Element X) {/ / return newNode
cout<<"]"<<endl<<"........................."<<endl; NODE* newNode = new NODE {X, NULL};
} if (newNode==NULL) return NULL;
// return a pointer to the node (NULL if not found) if (L.pHead==NULL) // SLL is empty
NODE* searchNode(const SLList L, int key) { L.pHead = L.pTail = newNode;
NODE * current = L.pHead; else {
while (current != NULL && current->data.key != key) L.pTail->pNext = newNode;
current = current->pNext; L.pTail = newNode;
return current; }
} return newNode; }
59
// insert a new node at position <Pos>, return to newNode void deletetNodeAtPosition(SLList &L, int Pos) {
NODE* insertNode(SLList &L, Element X, int Pos) { if (Pos==0) return deleteFirstNode(L);
if (Pos==0) return prependNode (L, X); NODE* q = L.pHead;
if (Pos==-1) return appendNode (L, X); for (int i=1; i<Pos && q!=NULL; i++) // find node at (Pos-1)
NODE* q = L.pHead; q = q->pNext;
for (int i=1; i<Pos && q!=NULL; i++) // find node at (Pos-1) if (q==NULL) return; // Pos > number of elemens
q = q->pNext; NODE *p = q->pNext; // <p> : the node must be delete
if (q==NULL) return NULL; // Pos > number of elemens if (p == NULL) return;
// insert <newNode> after node <q> q->pNext = p->pNext;
NODE* newNode = new NODE {X, q->pNext}; if (L.pTail==p) L.pTail = q;
if (newNode==NULL) return NULL; delete p;
q->pNext = newNode; }
if (q==L.pTail) L.pTail = newNode; void deleteNodeByKey(SLList &L, int Key) {
return newNode; if (L.pHead==NULL) return;
} if (L.pHead->data.key==Key) return deleteFirstNode(L);
NODE* addNode(SLList &L) { NODE* q = L.pHead, *p = q->pNext;
cout<<"Enter value of node: "; while (p!=NULL && p->data.key != Key) {
Element X; cin>>X.key; q = p; p = p->pNext; // <q> is always the previous of <p>
cout<<"Enter position to insert (-1 for append): "; }
int pos; cin>>pos; if (p==NULL) return; // not found
return insertNode(L, X, pos); q->pNext = p->pNext;
} if (L.pTail==p) L.pTail = q;
void deleteFirstNode(SLList &L) { delete p;
if (L.pHead == L.pTail) { //There is only one node }
delete L.pHead; void deleteNode(SLList &L) {
L.pHead = L.pTail = NULL; cout<<"Enter position to delete or -1 to delete by key): ";
return; int pos; cin>>pos;
} if (pos != -1) return deletetNodeAtPosition(L, pos);
NODE *p = L.pHead; cout<<"Enter the key of node: ";
L.pHead = L.pHead->pNext; int key; cin>> key;
delete p; deleteNodeByKey(L, key); // delete 1st node found
} }
60
void deleteList(SLList &L) { Head2 = Head2->pNext;
while (L.pHead) deleteFirstNode(L); current->pNext = L.pHead; // prepend <current> to list <L>
} L.pHead = current;
// return number of random elements are made }
int makeRandomList (SLList &L) { }
if (L.pHead != NULL) deleteList (L); void main() {
cout<<"Enter number of elements: "; SLList List = {NULL, NULL}; //Init Empty List
int Num; cin>>Num; while (true) {
L.pHead = L.pTail= NULL; printList(List);
for (int i=0; i<Num; i++) { cout<<"0. Quit"<<endl
int random = (int)rand() % 2020; <<"1. Read Linked List from File"<<endl
Element X = {random, 1.0*random/99}; <<"2. Save Linked List to File"<<endl
if (!prependNode(L,X)) return i; <<"3. Make a random Linked List with N elements"<<endl
} <<"4. Update a node"<<endl
} <<"5. Add a node"<<endl
// reverse List by traverse list L1 and prepend to List L2 <<"6. Delete a node"<<endl
void reverseList (SLList L1, SLList &L2) { <<"7. Sort List"<<endl
if (L1.pHead == NULL) return; <<"8. Reverse List"<<endl
L2.pHead = L2.pTail = NULL; <<"9. Remove duplicate elements"<<endl;
while (L1.pHead != NULL) { cout<< endl<< "Enter operation number: ";
prependNode(L2, L1.pHead->data); int choice; cin>> choice;
L1.pHead = L1.pHead->pNext; switch (choice){
} case 0: deleteList(List); return 0;
deleteList(L1); case 3: makeRandomList(List); break;
} case 4: updateNode(List); break;
void reverseList (SLList &L){ // traverse & prepend to new-list case 5: addNode(List); break;
if (L.pHead == NULL) return; case 6: deleteNode(List); break;
NODE *Head2 = L.pHead->pNext; // mov List to <Head2> case 8: reverseList(List); break; //or reverseList(List, List);
L.pHead->pNext = NULL; default: cout<<"You need to enter a number between 0 & 9";
L.pTail = L.pHead; }
while (Head2 != NULL) { }
NODE * current = Head2; }
61
#include <iostream> while (p != NULL) {
#define MAX 1234 Num++;
#define _INC 101 p = p->pNext;
using namespace std; }
typedef struct Student { return Num;
char Id[10]; }
char Name[30]; // chuyen mang dong A vao xau L
float Point; // maybe more if you want // tra ve so phan tu chuyen duoc
} Element; int Array2LinkedList(ARRAY A, LIST & L) {
L.pHead = L.pTail = NULL; //tao xau rong
typedef struct Node { for (int i = A.num - 1; i >= 0; --i)
Element data; if (!prependNode(L,A.items[i]))
struct Node * pNext; return A.num - 1 - i;
}NODE; return A.num;
typedef struct { }
Element * items; /*
int capacity; // mang A -> xau L khi co con tro cuoi xau
int num; int Array2LinkedList(ARRAY A, LIST & L) {
}ARRAY; L.pHead = L.pTail = NULL; //tao xau rong
typedef struct { for (int i = 0; i<A.num; i++)
NODE * pHead; if (!appendNode(L, A.items[i]))
NODE * pTail; return i + 1;
}LIST; return A.num;
// Dem so phan tu cua xau L }
int sizeOf(const LIST L) { */
int Num = 0;
NODE * p = L.pHead;
62
// chuyen xau L vao mang dong A A.items = p;
// giai phong xau L neu co <Free> bat break;
bool List2Array(LIST &L, ARRAY &A, bool Free) { }
A.num = sizeOf(L); }
A.capacity = A.num + _INC; if (Inc <= 0) return false;
A.items = new Element[A.capacity]; A.capacity += Inc;
if (A.items == NULL) { }
A.capacity = A.num = 0; return true; }
return false; // Tao ngau nhien xau <L> voi <n> phan tu
} int makeRandom(LIST &L, int n) {
NODE *p = L.pHead; L.pHead = L.pTail = NULL;
for (int i = 0; i<A.num; i++, p=p->pNext) for (int i = 0; i<n; i++) {
A.items[i] = p->data; Element X = makeRandom();
if (Free) // giai phong xau L if (!prependNode(L, X)) return false;
while (L.pHead) { }
p = L.pHead; return true; }
L.pHead = p->pNext; // Tao ngau nhien mang dong <A> voi <n> phan tu va
delete p; <sz> vi tri, return FALSE neu ko tao duoc
} bool makeRandom(ARRAY &A, int n, int sz=MAX) {
return true; } if (n < MAX) A.capacity = sz;
// Mo rong danh sach them <Inc> phan tu else A.capacity = n + 100;
//IF ko dc: bot 10 den khi dc OR (Inc<=0) A.items = new Element[A.capacity];
bool extendArray(ARRAY &A, int Inc = 101) { if (A.items == NULL) return false;
for (; Inc > 0; Inc -= 10) { A.num = n;
Element* p = (Element*)realloc(A.items, for (int i = 0; i < A.num; i++)
(A.capacity + Inc)*sizeof(Element)); A.items[i] = makeRandom();
if (p != NULL) { return true; }
63
// Xuat noi dung cua phan tu X ra man hinh
void Print(Element X) // CT chinh minh hoa
{ void main()
cout << "{"<<X.Id<<"# "<< X.Name<<"}"; {
} ARRAY A;
// Xuat mang A theo tung trang 100 hoac P phtu // tao ngau nhien mang dong A
void Print(ARRAY A, int p = 100) if (!makeRandom(A, 50, 1234567)) return;
{ cout << "* MANG DONG:" <<endl;
for (int i = 0; i < A.num; i++) { Print (A, A.num + 1); system("pause");
cout << "\t#" << i + 1 << ". ";
Print(A.items[i]); LIST L;
if (i % num == p - 1) cin.get(); Array2LinkedList(A, L); //
} cout << "* XAU:"<<endl;
cout << endl; Print(L); system("Pause");
}
// Xuat tat ca cac phtu trong xau L ARRAY B;
void Print(const LIST L) LinkedList2Array(L, B, true);
{ cout << "* MANG DONG:" << endl;
NODE * current = L.pHead; Print(B); system("Pause");
int num = 0; }
while (current != NULL) {
cout << "\t#" << ++num << ". ";
Print(current->data);
current = current->pNext;
}
cout << endl;
}
64
// Tao ngau nhien noi dung cua 1 phan tu
Element makeRandom()
{
Element X;
int random = (int)rand() % 2020;
//strcpy_s(X.Id, 5, "IT20");
_itoa_s(random, X.Id + 0, 5, 10);
X.Point = 10.0*random / 2020;
char * Ho[19] = { "Nguyen", "Tran", "Le", "Pham", "Huynh", "Phan", "Vu", "Vo",
"Dang", "Bui", "Do", "Ho", "Ngo", "Duong", "Ly", "Trinh", "Ha", "Thai", "" };
char * Lot[3] = { "Van", "Thi", "" };
char * Ten[18] = { "Xuan", "Ha", "Thu", "Dong", "Tay", "Nam", "Bac", "Trung", "Dai",
"Cuc", "Mai", "Dao", "Le", "Nho", "Cam", "Quit", "Buoi", "Tac" };
X.Name[0] = 0;
strcat_s(X.Name, Ho[rand() % 18]);
strcat_s(X.Name, " ");
int iTenLot = rand() % 3;
if (iTenLot != 2) strcat_s(X.Name, Lot[iTenLot]);
else {
iTenLot = rand() % 19;
if (strncmp(Ho[iTenLot], X.Name, strlen(Ho[iTenLot])))
strcat_s(X.Name, Ho[rand() % 18]);
}
strcat_s(X.Name, " "); strcat_s(X.Name, Ten[rand() % 18]);
return X;
}
65
• Addition
• Prepend
• Append
• After a node
• Before a node
• Deletion
• First node
• After a node
67
• Create Node:
newNode = new NODE {X, NULL, NULL};
• DLL is empty:
pHead = pTail = newNode;
• DLL is not empty:
newNode->pNext = pHead;
pHead->pPre = newNode;
pHead = newNode;
68
• DLL is empty:
newNode = new NODE {X, NULL, NULL};
pHead = pTail = newNode;
NODE * r = q->pPre; //=> must insert after <r> and before <q>
q->pPre = newNode;
newNode->pNext = q;
if (r != NULL) {
r->pNext = newNode;
newNode->pPre = r;
}
else // <q> == <pHead>
pHead = newNode;
71
In DLL:
• How to insert a node at a given position ?
• How to delete the last node ?
• How to delete a node before node <q>?
• How to delete a node at a given data ?
• How to delete a node at a given position ?
• How to delete all nodes ?
75
• Addition
• Prepend
• Append
• After a node
• Before a node
• Deletion
• First node
• After a node
76
• CLL is empty:
newNode = new NODE {X, NULL};
newNode->pNext = newNode;
pHead = pTail = newNode;
• CLL is not empty:
newNode = new NODE {X, NULL};
newNode->pNext = pHead;
pHead = newNode;
pTail->pNext = pHead;
77
• CLL is empty:
newNode = new NODE {X, NULL};
newNode->pNext = newNode;
pHead = pTail = newNode;
p = pHead;
while (p->pNext != q) //find previous node of <q>
p = p->pNext;
//=> must insert <newNode> after <p> and before <q>
p->pNext = newNode;
newNode ->pNext = q;
if (q == pHead)
pHead = newNode;
80
In CLL:
• Create Node:
newNode = new NODE {X, NULL};
• SLL (without a header node):
if (pHead==NULL)
pHead = pTail = newNode;
else {
newNode->pNext = pHead;
pHead = newNode;
}
• HLL (with a header node):
pHead->pNext = newNode;
if (pTail== pHead)
pTail = newNode;
86
STACKS
https://www.proofof.blog/2018/07/01/stack-queue.html
91
struct Stack {
bool Push(Stack &S, Element X)
Element * items;
{
int capacity; // max size of stack
if (S.top == S.capacity)
int top; // stack top
}; return false;
void Init(Stack &S, int size) S.items[S.top++] = X;
{
S.items = new Element[size]; return true;
S.capacity = size; }
S.top = 0;
} Element Pop(Stack &S)
bool isEmpty(Stack S) {
{
return (S.top==0); return S.items[--S.top];
}
}
96
QUEUES
https://www.proofof.blog/2018/07/01/stack-queue.html
99
BT#01: VCT hỗ trợ người dùng thực hiện các phép tính cộng - trừ - nhân - chia
trên 2 phân số sao cho việc sử dụng con trỏ là nhiều nhất có thể.
(con trỏ được dùng ít nhất ở các chỗ: trỏ đến địa chỉ các phân số, trỏ đến tử & mẫu
của mỗi phân số, là tham số của hàm, lưu địa chỉ kết quả của hàm, làm con trỏ hàm)
BT#02: So sánh mảng tĩnh và mảng động 1 chiều; mảng tĩnh và mảng động 2 chiều
b/ Thao tác Hủy 1 phần tử trên danh sách liên kết đơn và mảng 1 chiều.
a/ Linked List có và không có con trỏ Tail luôn lưu địa chỉ Node cuối.
BT#05: Viết hàm chuyển danh sách sinh viên đang lưu trong một mảng động vào
a) danh sách liên kết đơn không có con trỏ cuối và ngược lại.
b) danh sách liên kết đơn luôn có con trỏ cuối và ngược lại.
b) xâu đơn có thứ tự + có và không có con trỏ cuối (2 hàm khác nhau).
c) xâu đơn có thứ tự + có Header node + có và không có con trỏ cuối (2 hàm khác nhau).
d) xâu đơn có thứ tự + có Header node và luôn có địa chỉ node cuối nằm trong các byte đầu
của trường dữ liệu trong Header node.
107
BT#07: Viết hàm xóa phần tử cuối trên
a) mảng.
b) xâu đơn có và không có con trỏ cuối (2 hàm khác nhau).
c) xâu đơn có Header node + có và không có con trỏ cuối (2 hàm khác nhau).
d) xâu đơn có Header node chứa địa chỉ node cuối trong các byte đầu của trường dữ liệu.
BT#11: Viết hàm tạo 2 mảng Index (sắp theo thứ tự tang) trên 2 khóa khác nhau với 1 danh
sách đang lưu ở
a) mảng.
b) xâu.
BT#12: Chỉ ra 1 ví dụ cụ thể cần áp dụng cấu trúc danh sách đa liên kết. Khai báo và viết
hàm xuất danh sách tương ứng.
109
BT03.a: So sánh ưu khuyết điểm của thao tác Thêm 1 phần tử trên xâu đơn & mảng
Độ phức tạp Cao: có nhiều tr/h ứng Ko thấp: xử lý như mảng tĩnh,
Thấp: Có thể quy
với nhiều cách xử lý khác nhưng khi mảng đầy phải tái cấp
(khi code) về đúng 01 tr/h
nhau phát hơi rắc rối (3)
* Các ưu khuyết điểm khi Thêm phần tử vào Đầu danh sách:
Rất nhanh – là tr/h Khá chậm –vì phải dồn Thường chậm hơn hẳn mảng tĩnh
Tốc độ
nhanh nhất toàn bộ phần tử ra sau vì kích thước lớn hơn hẳn
Độ phức tạp Ko đơn giản, phải có xử Hơi phức tạp, nếu phải có thêm
Khá đơn giản
(khi code) lý dồn các phần tử thao tác tái cấp phát khi mảng đầy
Ưu khuyết điểm khi Thêm phần tử vào Sau 1 phần tử trong DS: (ko phải phần tử cuối)
XÂU ĐƠN MẢNG TĨNH MẢNG ĐỘNG
Phải duyệt tìm phần tử Không nhanh do phải Thường chậm hơn mảng
Tốc độ
nhưng cũng khá nhanh dồn mảng tĩnh vì kích thước lớn hơn
Không đơn giản, phải xét Như mảng tĩnh, phức tạp
Độ phức tạp Không phức tạp
các tr/h đặc biệt hơn khi phải tái cấp phát.
Mức độ sử dụng Cao Không cao Không cao
Ưu khuyết điểm khi Thêm phần tử vào Sau 1 phần tử trong DS: (ko phải phần tử cuối)
XÂU ĐƠN MẢNG TĨNH MẢNG ĐỘNG
Phải duyệt tìm phần tử kế Không nhanh do phải Thường chậm hơn mảng
Tốc độ
trước nhưng vẫn nhanh dồn mảng tĩnh vì kích thước lớn hơn
Không đơn giản, phải xét Như mảng tĩnh, phức tạp
Độ phức tạp Không phức tạp
các tr/h đặc biệt hơn khi phải tái cấp phát.
Mức độ sử dụng Thấp Cao Không cao
Ưu khuyết điểm khi Thêm phần tử vào danh sách có thứ tự:
Đây là thao tác tổng hợp – tùy theo giá trị phần tử mà vị trí thêm sẽ là vào đầu, vào cuối, hay
vào sau 1 phần tử; ở mức bình thường thì tr/h hay xảy ra sẽ là thêm vào sau 1 phần tử. Nhìn
chung là tốc độ chạy trên xâu sẽ nhanh hơn hẳn nhưng việc code sẽ hơi phức tạp hơn.
112
Ghi chú:
(1): Với mảng tĩnh thì ko thể thêm được khi số phần tử của mảng đã bằng với số phần tử tối đa
được khai báo, còn mảng động trong tr/h này phải tái cấp phát và có thể ko còn đủ bộ nhớ để
cấp – nếu đủ thì việc cấp và chép lại mảng sang vị trí mới cũng mất nhiều thời gian. Tr/h khi cấp
phát mảng động có dự phòng cấp dư 1 số phần tử thì thường sẽ thành công.
(2a): Do chỉ phải cập nhật 2 con trỏ + duyệt 1 phần của xâu (số byte phải làm việc khá nhỏ).
(2b): Vì thường phải thực hiện thao tác chép dồn 1 phần mảng và phải làm việc với nhiều byte
hơn (số byte phải làm việc = <kích thước phần tử>*<số phần tử phải dồn> có thể rất lớn)
(3): Cụ thể tr/h thêm vào đầu chính là thêm ở vị trí 0, thêm vào cuối là thêm ở vị trí N (với mảng
có N phần tử), thêm vào sau phần tử K là thêm ở vị trí K+1, thêm vào trước phần tử K là thêm ở
vị trí K-1; và tất cả các tr/h trên đều quy về thao tác thêm phần tử vào vị trí M trên mảng.
(4): Các tr/h đặc biệt chủ yếu là xâu rỗng, thêm vào trước /sau 1 phần tử mà phần tử này là đầu
/cuối xâu & quên cập nhật lại con trỏ đầu /cuối xâu,…
(5): Là thao tác có tính điển hình, có độ quan trọng cao & thường hay gặp trên DS (mà khi nắm
được thì có thể hiểu về cấu trúc và làm được nhiều xử lý khác nhau). Nếu ko thực hiện được thao tác
thêm vào DS thì cũng sẽ không tồn tại DS các phần tử để mà CT có thể xử lý (tức CT ko thể chạy)
End!