資料結構與演算法碎片積累(二)
背景:非科班梳理基礎知識ing
前言:資料結構與演算法碎片積累(一)有60個小題(20節課),感覺看起來太多了,所以,接下來根據課程安排,採用課程內容分類方式來總結。這樣子,或許回頭看時候,更人性化一些。
20201124
1、啥叫雙向連結串列?
答:簡單理解,就是一個節點,由資料域data,有前指標prior,指標next組成。
typedef char ElemType;
typedef struct DualNode {
ElemType data;
struct DualNode* prior;//前驅結點
struct DualNode* next;//後繼結點
};
2、雙向連結串列插入和刪除操作是怎麼樣的?
答:
1)插入:
假設節點s插到節點p的前方,核心語句:
s->next=p;//s的後指標指向p
s->prior=p->prior;//s的前指標指向p的前一個結點
p->prior->next=s;//p的前一個結點的後指標指向s
p->prior=s;//p的前指標指向s
插入操作時候,一定要注意指標的指向以及先後順序
2)刪除:
假設節點p為待刪除節點,關鍵語句:
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);//釋放刪除節點所佔的記憶體
關鍵就是把節點p的前節點的後指標指向p的後節點;p的後節點的前指標指向p的前結點,釋放節點p內容。
3、雙向連結串列相對於單連結串列來說,有啥特色?
答:
1)雙向連結串列相對單連結串列而言,更復雜一些,每個節點多一個prior指標,對於插入和刪除操作的順序一定要注意;
2)雙向連結串列可以有效提升演算法的時間效能,也就是利用空間換取時間。
3)簡單理解,雙向連結串列有前後指向指標,指向更加靈活。
4、雙向連結串列的應用例項演示。
答:
–要求實現使用者輸入一個數使得26個字母的排序發生變化,例如使用者輸入3,輸出結果:
DEFGHIJKLMNOPQRSTUVWXYZABC
–同時需要支援負數,例如使用者輸入-3,輸出結果:
XYZABCDEFGHIJKLMNOPQRSTUVW
//26字母輸出,練習雙向連結串列
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef char ElemType;
typedef int Status;
//雙向連結串列
typedef struct DualNode {
ElemType data;
struct DualNode* prior;//前驅結點
struct DualNode* next;//後繼結點
}DualNode, * DuLinkList;
//初始化一個雙向連結串列,以及插入資料到雙向連結串列中
Status InitList(DuLinkList* L)
{
DualNode* p, * q;//節點指標
int i;
*L = (DuLinkList)malloc(sizeof(DualNode));
if (!(*L))
{
return ERROR;
}//開闢失敗,退出函式
(*L)->next = (*L)->prior = NULL;
p = *L;
for (i = 0; i < 26; i++)//依次將26個字母插入到連結串列中
{
q = (DualNode*)malloc(sizeof(DualNode));//開闢新結點
if (!q)
{
return ERROR;//開闢失敗,退出
}
q->data = 'A' + i;//這種方式儲存26個字母到雙向連結串列裡面
q->prior = p;
q->next = p->next;//注意,最開始的p->next都是NULL的,這一步
//保持了連結串列的最後一個結點的後指標都是指向NULL
//所以,這一步一定要注意,順序不能和下一步調換
p->next = q;
p = q;//移動p到連結串列的最後面
if (i == 25)//下面註釋步驟作用和這裡是一樣的
{
p->next = (*L)->next;
(*L)->next->prior = p;
}//這一步實現雙向迴圈連結串列(注意,這個迴圈雙向連結串列,不連線頭結點*L的)
}
//p->next = (*L)->next;
//(*L)->next->prior = p;//實現最後結點和字元A結點連結(注意不是頭結點*L)
return OK;
}
//這函式作用是控制表頭*L指標的移動步數,從而達到輸出字母的順序要求
void Caesar(DuLinkList* L, int i)
{
if (i > 0)
{
do {
(*L) = (*L)->next;//這裡決定了後移
} while (--i);//由於i大於0,所以要減少來控制後移步數
}
if (i < 0)
{
do {
(*L) = (*L)->prior;//這裡決定了前移
} while (++i);//由於i小於0,所以要增加來控制後移步數
}
}
int main()
{
DuLinkList L;
int i,n;
InitList(&L);
printf("請輸入一個整數:");
scanf_s("%d", &n);//這裡由於在vs上面執行的,提示了scanf不安全
//需要寫成scanf_s型別
Caesar(&L, n);
for (i = 0; i < 26; i++)
{
L = L->next;
printf("%c", L->data);
}
return 0;
}
5、棧是啥?
答:可以這麼理解:
1)棧是一種線性表;
2)棧是一種先進後出(如子彈入彈夾)的資料結構;
3)棧的刪除或插入操作只是在表尾(又稱棧頂top)進行;
4)棧的表尾,又稱棧頂(top);表頭,又稱為棧底(bottom)。
5)棧的插入操作(push),稱為進棧,也稱為壓棧;刪除操作(pop),叫出棧,又稱為彈棧;
6)棧有兩種儲存方式,順序儲存結構和鏈式儲存結構。
6、棧的常規操作,結構定義,入棧,出棧,清空棧,銷燬棧是哈?
答:案例展示,將一個二進位制數轉為十進位制數:
//利用棧的資料結構特點,將二進位制轉換為十進位制數
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define STACK_INIT_SIZE 20
#define STACKINCREMENT 10
//棧結構定義
typedef char ElemType;
typedef struct {
ElemType* top;//棧頂
ElemType* base;//棧底
int stackSize;//棧空間大小
}sqStack;
void InitStack(sqStack* s) {
s->base = (ElemType*)malloc(STACK_INIT_SIZE * sizeof(ElemType));//開闢空間
if (!s->base)
return;//開闢失敗則退出函式
s->top = s->base;//剛開始棧頂棧底指向相同
s->stackSize = STACK_INIT_SIZE;//初始化棧空間大小
}//初始化一個棧
//入棧操作
void Push(sqStack* s, ElemType e)
{
if (s->top - s->base >= s->stackSize)//檢測棧是否已經滿了
{
s->base = (ElemType*)realloc(s->base, (s->stackSize + STACKINCREMENT)*sizeof(ElemType));
//複製原來的資料,並開闢到更大的記憶體中
if (!s->base)
return;//開闢失敗的話,退出函式
s->stackSize = s->stackSize + STACKINCREMENT;//棧容量不跟新,會導致程式崩潰(qt執行倒不會)
}
*(s->top) = e;//插入元素入棧
s->top++;//棧頂上移
}
//出棧操作
void Pop(sqStack* s, ElemType* e)
{
if (s->top == s->base)
return;//判斷是否出現下溢
*e = *--(s->top);//先棧頂元素下移,然後,返回出棧元素
}
//清空棧操作
void ClearStack(sqStack* s)
{
s->top = s->base;
}//將棧頂指標指向棧底,就不再讀取棧資料,達到清空目的(清空不表示資料刪除;銷燬才是將資料徹底銷燬)
//銷燬一個棧
void DestoryStack(sqStack* s)
{
int i, len;
len = s->stackSize;
for (i = 0; i < len; i++)
{
//ElemType* p;
//p = s->base;
//s->base++;
//free(p);
free(s->base);
s->base++;
}//這裡存在一個bug,還沒有解決20201124
s->base = s->top = NULL;
s->stackSize = 0;
}//從棧底不斷上移,並釋放記憶體
int StackLen(sqStack s)//對比上面的可以發現,對應需要修改的,傳指標;
//不需要修改資料的,只是傳值
{
return(s.top - s.base);
}
int main()
{
ElemType c;
sqStack s;
InitStack(&s);//初始化棧
int len, i, sum = 0;
printf("請輸入二進位制數,輸入#符號表示結束!\n");
scanf_s("%c", &c);
while (c != '#')
{
Push(&s, c);
scanf_s("%c", &c);//這裡的c是下一個入棧的字元
//printf("%c\n", c);
}
getchar();//Enter鍵,產生的字元'\n'(==10),該函式可避免
//該字元一直在緩衝區(下次輸入操作時候,10會造成程式混亂)
//其作用就是將'\n'從緩衝區去掉
len = StackLen(s);
printf("棧的當前容量是:%d\n", len);
for (i = 0; i < len; i++)
{
Pop(&s,&c);
sum = sum+(c - 48) * pow(2, i);//pow就是被呼叫的數學次方函式
}
printf("轉換為十進位制數是:%d\n", sum);
ClearStack(&s);
int k = StackLen(s);
if (k == 0) {
printf("\n清空成功!\n");
}
//DestoryStack(&s);//銷燬棧還有bug,後面修正了再更新,銷燬思路應該沒問題的
return 0;
}
7、棧的鏈式儲存結構插入和刪除的操作注意點?
答:
棧因為只是棧頂用來做插入和刪除操作,所以比較好的方法就是將棧頂放在單連結串列的頭部,棧頂指標和單連結串列指標合二為一。棧的鏈式儲存結構圖示可如:
typedef struct StackNode {
ElemType data;//存放棧的資料
struct StackNode* next;
}StackNode,*LinkStackPtr;//棧節點,鏈棧節點指標
typedef struct LinkStack {
LinkStackPtr top;//top指標
int count; //棧元素計算器
};
//進棧操作
//對於棧鏈的Push操作,假設元素值為e的新節點是s,top為棧頂指標,那麼
Status Push(LinkStack* s, ElemType e)
{
LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode));//開闢棧節點
p->data = e;//儲存需要插入的元素
p->next = s->top;//把棧頂指標儲存
s->top = p;//把棧點放到原來棧頂位置,同時棧頂指標上移
s->count++;//棧的容量加1
return OK;
}
//出棧操作
Status Pop(LinkStack* s, ElemType* e) {
LinkStackPtr p;
if (StackEmpty(*s))//StackEmpty判斷是否為空棧,空的話返回1
return ERROR;
*e = s->top->data;//儲存刪除的元素
p = s->top;//記錄棧頂地址
s->top = s->top->next;//棧頂指標下移
free(p);//釋放原來棧頂記憶體
s->count--;//棧的容量減1
return OK;
}
8、鏈式棧的應用,逆波蘭計算器怎麼實現?
答:
1)正常表示式->逆波蘭表示式的感性認識:
a+b - > a b +
a+(b-c) -> a b c - +
a+(b-c)d -> a b c – d * +
a+d(b-c) -> a d b c - * +
2)程式碼實現,就是通過逆波蘭表示式來計算結果:
//逆波蘭計算器
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#define STACK_INIT_SIZE 20
#define STACKINCREMENT 10
#define MAXBUFFER 10
typedef double Elemtype;
typedef struct {
Elemtype* base;
Elemtype* top;
int stackSize;
}aqStack;
void InitStack(aqStack *s) {
s->base = (Elemtype*)malloc(STACK_INIT_SIZE * sizeof(Elemtype));
if (!s->base)
return;
s->top = s->base;
s->stackSize = STACK_INIT_SIZE;
}
void Push(aqStack* s, Elemtype e)
{
//棧滿,追加空間
if (s->top - s->base >= s->stackSize) {
s->base = (Elemtype*)realloc(s->base, (s->stackSize + STACKINCREMENT) * sizeof(Elemtype));
if (!s->base)
return;
s->top = s->base + s->stackSize;
s->stackSize = s->stackSize + STACKINCREMENT;
}
*(s->top) = e;
s->top++;
}
void Pop(aqStack* s, Elemtype* e)
{
if (s->top == s->base)
return;
*e = *--(s->top);//將棧頂元素彈出並修改棧頂指標
}//出棧
int StackLen(aqStack s)
{
return(s.top - s.base);
}
int main() {
aqStack s;//例項化一個棧物件
char c;//儲存輸入的字元
double d, e;//用於接收出棧入棧元素
char str[MAXBUFFER];//小數的緩衝器
int i=0;
InitStack(&s);//初始化棧
printf("請按逆波蘭表示式輸入待計算資料,資料間、資料與運算子間,運算子間之間用空格隔開,以#號作為結束標誌:\n");
scanf_s("%c", &c);
while (c!='#') {//這裡注意的是,這裡的c還是一個一個字元讀取進來的
while (isdigit(c)||c=='.') {//用於過濾數字
//該while迴圈,在不碰到空格前,會繼續遍歷c下一個字元
//isdigit()屬於ctype庫函式中,檢測是十進位制數字符(0~9)返回非零,否則返回0
str[i++] = c;//儲存載入進來的字元
str[i] = '\0';//'\0'在字串中表示結束意思,必須加上這個,否則除錯會錯誤
//通過測試發現,如果不加這個結束符,會導致上一個字元段的保
//存的字元會繼續存在並使用,這裡原因是,i=0的作用是重新從陣列的
//第一個開始重新賦值儲存,所以每次都要新增結束符,保證不會讀取到
//原來遺留在陣列中的資料
if (i >= 10) {
printf("出錯:輸入單個資料過大!\n");
return -1;
}
scanf_s("%c", &c);//驅使繼續讀取c下一個字元
if (c == ' ')//如果碰到空格
{
d = atof(str);//atof()函式是將儲存在str陣列裡面的字串轉換為浮點型資料
Push(&s, d);//轉化的浮點數入棧
i = 0;//為下一次c字元組成的串轉換為浮點數做準備
printf("%f\n", d);//測試獲取得到的浮點數
break;//第一個引數入棧成功就跳出該迴圈,進入下一個字元c的讀取
}
}
switch (c) {
case '+':
Pop(&s,&e);
Pop(&s, &d);
Push(&s, d + e);//為啥這裡可以使用d,e呢?很簡單,因為,有了出棧帶來的引數
break;
case'-':
Pop(&s, &e);
Pop(&s, &d);
Push(&s, d - e);
break;
case'*':
Pop(&s, &e);
Pop(&s, &d);
Push(&s, d * e);
break;
case'/':
Pop(&s, &e);
Pop(&s, &d);
if (e != 0) {
Push(&s, d / e);
}
else {
printf("\n出錯:除數為零!");
return -1;
}
break;
}
scanf_s("%c", &c);//驅使繼續讀取c下一個字元,而且在上一個內在的while迴圈內讀取過的c字元是不會再重複讀取的,
//而是繼續讀取,這裡感覺好像使得c在迴圈裡面成為全域性變數,遍歷過的就接著下一個遍歷
}
Pop(&s,&d);
printf("\n最終的計算結果為:%f\n", d);
return 0;
}
9、如何實現從中綴表示式轉換為字尾表示式?
答:
1)感性認識,中綴表示式->字尾表示式
(1-2)*(4+5)->1 2 – 4 5 + *
2)逆波蘭表示式(RPN),是不需要括號的字尾表示式
3)相對於中綴表示式(人比較容易理解),字尾表示式更適合計算機,因為,字尾運算時候,計算機不需不斷判斷。
4)中綴轉字尾程式碼實現:
//將中綴表示式轉為字尾表示式
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define STACK_INIT_SIZE 20
#define STACKINCREMENT 10
typedef char ElemType;
typedef struct {
ElemType* top;
ElemType* base;
int stackSize;
}sqStack;//棧
void InitStack(sqStack* s) {
s->base = (ElemType*)malloc(STACK_INIT_SIZE * sizeof(ElemType));
if (!s->base)
return;
s->top = s->base;
s->stackSize = STACK_INIT_SIZE;
}//初始化一個棧
void Push(sqStack* s, ElemType e)
{
if (s->top - s->base >= s->stackSize)//檢測棧是否已經滿了
{
s->base = (ElemType*)realloc(s->base, (s->stackSize + STACKINCREMENT) * sizeof(ElemType));
//複製原來的資料,並開闢到更到的記憶體中
if (!s->base)
return;
s->stackSize = s->stackSize + STACKINCREMENT;//棧容量不跟新,會導致程式崩潰(qt執行倒不會)
}
*(s->top) = e;
s->top++;
}//入棧操作
void Pop(sqStack* s, ElemType* e)
{
if (s->top == s->base)
return;//判斷是否出現下溢
*e = *--(s->top);
}//出棧操作
int StackLen(sqStack s)//對比上面的可以發現,對應需要修改的,傳指標;
//不需要修改資料的,只是傳值
{
return(s.top - s.base);
}
int main() {
sqStack s;
char c, e;
InitStack(&s);
printf("請輸入中綴表示式,以#作為結束標誌:");
scanf_s("%c", &c);
while (c!='#')
{
while(c >= '0' && c <= '9')
{
printf("%c", c);
scanf_s("%c", &c);//這裡使用這個,可以會出現有#情況,但是,還有
//沒有回到最外面的while判斷#,所以需要在下面的
//輸入型別中新增#判斷,如果有,那麼跳出迴圈
if (c < '0' || c>'9') {
printf(" ");
}//這樣處理是為了,大於9的數值輸入的,如12,顯示時候,不分開
}
//數字判斷,如果是數字就直接列印
if(']'==c)//這裡和 c==']' 意義一樣的,不過,這裡寫少一個= ,
//使得變成了賦值語句,編譯器是檢測不出錯誤的;而寫成
//變數在右側,少寫=會提醒報錯的。(常量在左側,賦值
//操作會報錯)
{
Pop(&s, &e);//出棧
while ('['!=e)
{
printf("%c ", e);//列印出棧元素
Pop(&s, &e);//繼續出棧出棧
}//如果沒有遇到左括號,一直列印
}
//當輸入元素為右括號時候,需要把括號中運算子號出棧,並且把裡面+、-、*、/ 列印出來
//這模組的意思,就是把括號優先順序提升最高,把裡面的運算子列印出來,但是括號只是出棧,不用列印
else if ('+'==c||c=='-')
{
if (!StackLen(s))//如果棧為空
{
Push(&s, c);//入棧
}//如果棧為空,把符號元素儲存到棧中
else {
do {
Pop(&s, &e);//出棧,檢測棧頂元素
if ('[' == e) {
Push(&s, e);
}//如果是左括號,則左括號回棧
else
{
printf("%c ",e);
}//出棧的元素不是左括號,則列印
} while (StackLen(s)&&e!='[');//棧不為空並且出棧元素不為左括號都要進行
Push(&s, c);
}//棧不為空時,輸入的+或者-則跟棧頂元素比較,沒遇到左括號,都要出棧列印;
//遇到左括號,就把運算子入棧
}
//這模組就是判斷輸入+或者-時,分兩種情況,首先判斷棧是否為空,不為空則入棧;棧不為空,那麼輸入元素
//需要和棧頂元素比較,這時候,也分兩種情況,如果此時棧頂元素是左括號,那麼,就把元素入棧;否則,就
//一直列印出棧
//這裡,相當於把之前入棧的運算子+、-(不包含括號內的,上一模組已列印完畢),全部列印出棧
else if (c == '*' || c == '/' || c == '[') {
Push(&s, c);
}
//如果是*、/、[ 時候,那麼就把這幾個符號入棧
else if (c == '#') {
break;
}//這裡判斷第一個while有可能出現#情況,然後跳出迴圈
//當進行多數字(如,1000,就是4個字元組成的)判斷時候,存在一個內迴圈,如果此時已經碰到了#,不加處理
//,下面又有一個scanf_s(繼續讀取下一個),那麼就會使得讀取到一些未知區域,會導致出錯。
else
{
printf("\n輸入錯誤!\n");
return -1;
}
//如果輸入的是其他資訊,那麼就提示輸入錯誤
scanf_s("%c", &c);//繼續讀取下一個字元
}//當未讀取到#符號時候,就一直迴圈判斷,看到底是列印還是入棧,還是出棧
while (StackLen(s))
{
Pop(&s, &e);
printf("%c ", e);
}//當上面的大迴圈結束了,棧中還保留運算子的話,那麼依次從棧頂出棧並列印
return 0;
}
//注意,原來採用的是()括號的,後面發現,除錯視窗自動為中文輸入法,導致
//容易即使輸入方式為中文輸入也看不出來,所以,採用[]代替()
//雖然,通過分步除錯理清楚了每一步的作用,但是,內在的演算法思路還是沒有很清晰的層次樣式
10、佇列有啥特性?
答:
1)佇列,只能一端插入,另一端刪除的線性表;
2)佇列,是一種先進先出的線性表(注意與先進後出的棧區分)
3)佇列,可用順序表實現,也可以用連結串列實現;但,一般情況下,使用連結串列來實現,所以,又可簡稱為鏈佇列。
4)佇列的結構特性:
空佇列時,front和rear都指向頭結點
11、佇列全家桶(結構、入隊、出隊、銷燬操作)是啥?
答:案例展示:
#include <malloc.h>
#include<stdio.h>
#include <stdlib.h>
//鏈佇列的結構程式碼
#define ElemType char
typedef struct QNode {
ElemType data;
struct QNode* next;
}QNode,*QueuePrt;//節點結構
typedef struct
{
QueuePrt front, rear;//隊頭、隊尾指標
}LinkQueue;
//建立或者初始化一個佇列
void initQueue(LinkQueue* q) {
q->front = q->rear = (QueuePrt)malloc(sizeof(QNode));
if (!q->front)
exit(0);//這是一個函式,而return是一個關鍵字
q->front->next = NULL;
}
//入隊操作
void InsertQueue(LinkQueue* q, ElemType e) {
QueuePrt p;
p = (QueuePrt)malloc(sizeof(QNode));
if (p == NULL)
exit(0);
p->data=e;
p->next = NULL;
q->rear->next = p;//q的隊尾由原來指向null,重新指向新加入的p
q->rear = p;//將佇列q的隊尾指標重新指向最後一個節點
}
//出隊操作
void DeleteQueue(LinkQueue* q, ElemType* e) {
QueuePrt p;
if (q->front == q->rear)//空佇列情況
return;
//非空佇列情況
p = q->front->next;
*e = p->data;
q->front->next = p->next;
if (q->rear == p)//佇列只一個元素,而元素被出隊了;在釋放該空間前
//將該尾指標移動回來,和頭指標指向同一節點頭結點
q->rear = q->front;
free(p);//釋放刪除節點所佔記憶體
}
//銷燬佇列
int DestoryQueue(LinkQueue* q) {
if (1) {
while (q->front) {
q->rear = q->front->next;
free(q->front);
q->front = q->rear;
}
return 1;
}
}
//建立一個連結串列並初始化,入隊操作,出隊操作並銷燬
int main() {
LinkQueue s;
initQueue(&s);
char e,t;
int i = 0;
printf("請輸入字元並以#結尾:\n");
scanf_s("%c", &e);
while (e != '#') {
InsertQueue(&s, e);
i++;
scanf_s("%c", &e);
}
while (i--)
{
DeleteQueue(&s, &t);
printf("%c ", t);
}
int a=DestoryQueue(&s);
if (a == 1) {
printf("\n銷燬完畢\n");
}
system("pause");
return 0;
}
#########################
不積矽步,無以至千里
好記性不如爛筆頭
截圖歸原作者所有,致謝。
相關文章
- Java資料結構與排序演算法 (二)Java資料結構排序演算法
- 【資料結構與演算法】二叉樹資料結構演算法二叉樹
- 資料結構與演算法-資料結構(棧)資料結構演算法
- 資料結構與演算法-學習筆記(二)資料結構演算法筆記
- 資料結構與演算法-二分查詢資料結構演算法
- 資料結構與演算法:二叉排序樹資料結構演算法排序
- 資料結構與演算法課程筆記(二)資料結構演算法筆記
- 【資料結構與演算法】—— 二分查詢資料結構演算法
- 資料結構與演算法(二)佇列、棧、連結串列資料結構演算法佇列
- 資料結構與演算法資料結構演算法
- 資料結構:初識(資料結構、演算法與演算法分析)資料結構演算法
- 資料結構與演算法整理總結---二分查詢資料結構演算法
- 資料結構與演算法-表示式二叉樹資料結構演算法二叉樹
- 資料結構與演算法-kd二叉樹(kNN)資料結構演算法二叉樹KNN
- 資料結構與演算法-二叉查詢樹資料結構演算法
- 資料結構與演算法-二叉樹性質資料結構演算法二叉樹
- 資料結構與演算法-二叉樹遍歷資料結構演算法二叉樹
- 搜尋中常見資料結構與演算法探究(二)資料結構演算法
- 資料結構與演算法:圖形結構資料結構演算法
- python演算法與資料結構-什麼是資料結構Python演算法資料結構
- 資料結構與演算法02資料結構演算法
- 資料結構與演算法-堆資料結構演算法
- 資料結構與演算法03資料結構演算法
- 【JavaScript 演算法與資料結構】JavaScript演算法資料結構
- 資料結構與演算法(java)資料結構演算法Java
- python資料結構與演算法Python資料結構演算法
- 資料結構與演算法——字串資料結構演算法字串
- 資料結構與演算法——排序資料結構演算法排序
- 演算法與資料結構——序演算法資料結構
- 資料結構與演算法——概述資料結構演算法
- 【資料結構與演算法】bitmap資料結構演算法
- 資料結構與演算法 - 串資料結構演算法
- 資料結構與演算法(1)資料結構演算法
- python演算法與資料結構-演算法和資料結構介紹(31)Python演算法資料結構
- 資料結構與演算法之線性結構資料結構演算法
- 資料結構與演算法-kd二叉樹(基礎)資料結構演算法二叉樹
- 演算法與資料結構之二分搜尋樹演算法資料結構
- 【資料結構與演算法】二分鐘初識樹資料結構演算法