Chap 15 struct 與資料結構

64
1 1 /64 /64 Chap 15 struct Chap 15 struct 與與與 與與與 與與 與與 struct struct 可可可可 可可可可可可可可可可可可可 可可 一。 可可可可 可可可可可可可可可可可可可 可可 一。 st st ruct ruct 可可可可可可可可可可可可可可可可可可可可可可可可可可可可

description

Chap 15 struct 與資料結構. struct 可以在同一個名稱下擁有多種資料型態。使用 struct 能讓資料的存取和處理更為靈活。. struct 與資料結構. 15.1 struct 的宣告和使用 15.2  由 struct 構成的陣列 15.3 struct 資料型態與函數參數的傳遞 15.4 struct 實例的動態宣告 15.5  指標成員與資料結構 15.6 union 資料型態 15.7 enum 資料型態. struct 的宣告和使用. 組成份子稱為 成員 (member) 或 資料欄位 (data field) 。 - PowerPoint PPT Presentation

Transcript of Chap 15 struct 與資料結構

Page 1: Chap 15  struct 與資料結構

11/64/64

Chap 15 structChap 15 struct 與資料結與資料結構構

struct struct 可以在同一個名稱下擁有多種資料可以在同一個名稱下擁有多種資料型態。使用型態。使用 structstruct 能讓資料的存取和處理更為能讓資料的存取和處理更為靈活。靈活。

Page 2: Chap 15  struct 與資料結構

22/64/64

structstruct 與資料結構與資料結構

15.115.1    structstruct 的宣告和使用的宣告和使用 15.215.2  由 由 structstruct 構成的陣列構成的陣列 15.315.3    structstruct 資料型態與函數參數的傳遞資料型態與函數參數的傳遞 15.415.4    structstruct 實例的動態宣告實例的動態宣告 15.515.5  指標成員與資料結構 指標成員與資料結構 15.615.6    unionunion 資料型態資料型態 15.715.7    enumenum 資料型態資料型態

Page 3: Chap 15  struct 與資料結構

33/64/64

structstruct 的宣告和使用的宣告和使用

組成份子稱為組成份子稱為成員成員 (member) (member) 或或資料欄資料欄位位 (data field)(data field) 。。

成員可以是各種不同的資料型態 成員可以是各種不同的資料型態 (( 複複合式資料型態合式資料型態 )) 。。

關鍵字關鍵字 structstruct 是英文 是英文 structurestructure ( ( 結構結構 ) ) 的縮寫,此種資料結構又稱為的縮寫,此種資料結構又稱為記錄記錄 (rec(record)ord) 。。

Page 4: Chap 15  struct 與資料結構

44/64/64

structstruct 資料型態的宣告範例資料型態的宣告範例

EmployeeEmployee 包括的資料成員有包括的資料成員有 NameName ( ( 姓名姓名 )) 、、PhonePhone ( ( 電話號碼電話號碼 ) ) 以及以及 IdId ( ( 編號編號 ) ) 三種:三種:

struct Employeestruct Employee

{{

char Name[20];char Name[20];

char Phone[10];char Phone[10];

int Id; int Id;

}; }; // // 注意這要用到「注意這要用到「 ;; 」!」!

Page 5: Chap 15  struct 與資料結構

55/64/64

Struct Struct 在記憶體中的儲存方式在記憶體中的儲存方式

各成員的儲存位置是連續的:各成員的儲存位置是連續的:

Name Phone Id

Employee

Page 6: Chap 15  struct 與資料結構

66/64/64

使用使用 struct struct 資料型態定義變數資料型態定義變數

可以使用標準的定義敘述。例如:可以使用標準的定義敘述。例如: Employee Ea, Eb;Employee Ea, Eb;

定義了兩個名稱分別為定義了兩個名稱分別為 EaEa 和和 EbEb 的的 EmEmployeeployee 變數。變數。

由某一資料型態定義的變數稱為該資料由某一資料型態定義的變數稱為該資料型態的型態的實例 實例 (instance)(instance) 。。

Page 7: Chap 15  struct 與資料結構

77/64/64

定義變數時一併給予初始值定義變數時一併給予初始值

例如,上面的敘述可進一步寫成:例如,上面的敘述可進一步寫成: EmployeeEmployee    Ea = {"Ann", "0238412Ea = {"Ann", "02384125", 105};5", 105};

EmployeeEmployee    Eb = {"Joanne", "0354413Eb = {"Joanne", "03544132", 106};2", 106};

Page 8: Chap 15  struct 與資料結構

88/64/64

要存取要存取 EmployeeEmployee 變數的個別資料欄位變數的個別資料欄位

必需同時給定變數名稱和資料成員名稱,中間用一個必需同時給定變數名稱和資料成員名稱,中間用一個成員運算符號成員運算符號 (member operator)(member operator) 「「 .. 」隔開。例如:」隔開。例如:

Ea.Name Ea.Name // // 其值目前分別為 “其值目前分別為 “ Ann”Ann”Eb.Phone Eb.Phone // // 其值目前分別為“其值目前分別為“ 023841202384125”5”

Ea.Id Ea.Id // // 其值目前分別為其值目前分別為 105105

分別用來代表分別用來代表 EaEa 這個這個 EmployeeEmployee 變數的三個成員,變數的三個成員,其值目前分別為“其值目前分別為“ Ann”Ann” ,“,“ 02384125”02384125” 和和 105105 。這。這個語法基本上和我們在個語法基本上和我們在 10.110.1 節介紹的成員函數的語節介紹的成員函數的語法是一致的。法是一致的。

Page 9: Chap 15  struct 與資料結構

99/64/64

範例程式範例程式 TestStruct.cppTestStruct.cpp

如何使用如何使用 structstruct 宣告自訂的資料型態,宣告自訂的資料型態,以及各欄位內的資料如何存取。以及各欄位內的資料如何存取。

Page 10: Chap 15  struct 與資料結構

1010/64/64

範例程式 檔案 範例程式 檔案 TestStruct.cppTestStruct.cpp

// TestStruct.cpp// TestStruct.cpp

#include <iostream>#include <iostream>

using namespace std;using namespace std;

structstruct Employee Employee

{{

char Name[20];char Name[20];

char Phone[10];char Phone[10];

int Id; int Id;

};};

// ----- // ----- 主程式 主程式 --------------------------------------------------------

Page 11: Chap 15  struct 與資料結構

1111/64/64

int main()int main(){{ EmployeeEmployeeEa= {"Ann", "02384125", 105};Ea= {"Ann", "02384125", 105}; EmployeeEmployee Eb = {"Joanne", "03544132", 106}; Eb = {"Joanne", "03544132", 106};

cout << "Ea cout << "Ea 的資料是:的資料是: \n" \n" << "<< " 姓名 : 姓名 : " << Ea.Name << '\n'" << Ea.Name << '\n' << "<< " 電話號碼: 電話號碼: " << Ea.Phone << '\n'" << Ea.Phone << '\n' << "<< " 編號 : 編號 : " << Ea.Id << endl;" << Ea.Id << endl; cout << "Eb cout << "Eb 的資料是:的資料是: \n" \n" << "<< " 姓名 : 姓名 : " << Eb.Name << '\n'" << Eb.Name << '\n' << "<< " 電話號碼: 電話號碼: " << Eb.Phone << '\n'" << Eb.Phone << '\n' << "<< " 編號 : 編號 : " << Eb.Id << endl;" << Eb.Id << endl; return 0;return 0;}}

Page 12: Chap 15  struct 與資料結構

1212/64/64

執行結果 執行結果

Ea 的資料是:姓名 : Ann電話號碼: 02384125編號 : 105Eb 的資料是:姓名 : Joanne電話號碼: 03544132編號 : 106

Page 13: Chap 15  struct 與資料結構

1313/64/64

合併合併 structstruct 資料型態的宣告和變數的定義資料型態的宣告和變數的定義

例如:例如: struct struct {{ char Name[20];char Name[20]; char Phone[10];char Phone[10]; int Id; int Id;

}} Ea, Eb; Ea, Eb; 由於粗體字的部份本身就是已經是新定義的由於粗體字的部份本身就是已經是新定義的

資料型態之具體內容,不用再取個名稱來代資料型態之具體內容,不用再取個名稱來代表它。表它。

Page 14: Chap 15  struct 與資料結構

1414/64/64

比較資料型態變數的語法比較資料型態變數的語法

struct {char Name[20]; char Phone[10]; int Id;} Ea, Eb ;

資料型態 變數名稱

(實例)

int x, y ; 資料型態 變數名稱

Page 15: Chap 15  struct 與資料結構

1515/64/64

由由 structstruct 構成的陣列構成的陣列

結合陣列和結合陣列和 structstruct ,可以一次完成很多具有相,可以一次完成很多具有相同結構的同結構的 structstruct 變數的定義。變數的定義。

例如,可以使用例如,可以使用 Employee Officer[50];Employee Officer[50];

同時定義從同時定義從 Officer[0] Officer[0] 到到 Officer[49]Officer[49] ,共,共 5050個個 EmployeeEmployee 變數變數

Page 16: Chap 15  struct 與資料結構

1616/64/64

structstruct 陣列各欄位的資料陣列各欄位的資料

cout << Officercout << Officer[8][8].Name << endl;.Name << endl;

cout << Officercout << Officer[12][12].Phone << endl;.Phone << endl;

cout << Officercout << Officer[40][40].Id << endl;.Id << endl;

Page 17: Chap 15  struct 與資料結構

1717/64/64

範例程式範例程式 StructArray.cppStructArray.cpp

允許使用者逐一輸入各陣列元素的各成員值 允許使用者逐一輸入各陣列元素的各成員值 (( 每輸入一個項目後,要按兩次每輸入一個項目後,要按兩次 EnterEnter 鍵鍵 )) 。。

Page 18: Chap 15  struct 與資料結構

1818/64/64

範例程式 檔案 範例程式 檔案 StructArray.cppStructArray.cpp

// StructArray.cpp// StructArray.cpp#include <iostream>#include <iostream>using namespace std;using namespace std;

const int NameSize = 20;const int NameSize = 20;const int PhoneSize = 10;const int PhoneSize = 10;struct Employeestruct Employee{{

char Name[NameSize];char Name[NameSize];char Phone[PhoneSize];char Phone[PhoneSize];

};};int main()int main(){{ const int Size = 2;const int Size = 2; Employee Officer[Size];Employee Officer[Size]; cout << "cout << " 共 共 " << Size << " " << Size << " 個 個 OfficersOfficers :: \n"; \n";

Page 19: Chap 15  struct 與資料結構

1919/64/64

for (int i=0; i<Size; i++)for (int i=0; i<Size; i++) {{ cout << "cout << " 請輸入 請輸入 Officer[" << IOfficer[" << I    << "] << "] 的姓名: 的姓名: ";"; cin.getline(Officer[i].Name, NameSize, '\n');cin.getline(Officer[i].Name, NameSize, '\n'); cout << "cout << " 電話號碼: 電話號碼: ";"; cin.getline(cin.getline(Officer[i].PhoneOfficer[i].Phone, PhoneSize, '\n');, PhoneSize, '\n'); }} for (int i=0; i<Size; i++)for (int i=0; i<Size; i++) {{ cout << "Officer["cout << "Officer[" << i << "] << i << "] 的資料是:的資料是: \n"\n" << "<< " 姓名 : 姓名 : "" << << Officer[i].NameOfficer[i].Name << '\n' << '\n' << "<< " 電話號碼: 電話號碼: " " << << Officer[i].PhoneOfficer[i].Phone << '\n'; << '\n'; }} return 0;return 0;}}

Page 20: Chap 15  struct 與資料結構

2020/64/64

執行結果執行結果

共 2 個 Officers :請輸入 Officer[0] 的姓名: Alan John電話號碼: 03-4521234

請輸入 Officer[1] 的姓名: Peter Pan電話號碼: 02-4354512Officer[0] 的資料是:姓名 : Alan John電話號碼: 03-4521234Officer[1] 的資料是:姓名 : Peter Pan電話號碼: 02-4354512

Page 21: Chap 15  struct 與資料結構

2121/64/64

structstruct 資料型態與函數參數的傳遞資料型態與函數參數的傳遞

由由 structstruct 所定義的實例被用來做為參數傳遞時,所定義的實例被用來做為參數傳遞時,其預設的語意是其預設的語意是傳值傳值 (pass-by-value)(pass-by-value) 。。

也就是說,在「被呼叫函數」內部將另外產也就是說,在「被呼叫函數」內部將另外產生一個複製資料,而不會影響「呼叫函數」生一個複製資料,而不會影響「呼叫函數」內的資料。內的資料。

Page 22: Chap 15  struct 與資料結構

2222/64/64

用用 structstruct 所定義的實例來傳遞參數所定義的實例來傳遞參數 例如,呼叫敘述可以寫成:例如,呼叫敘述可以寫成: ShowMember(Ea);ShowMember(Ea); 而被呼叫函數則可以定義成:而被呼叫函數則可以定義成: void ShowMember(Employee A)void ShowMember(Employee A) {{ cout << "cout << " 資料的詳細內容是:資料的詳細內容是: \n" \n" << "<< " 姓名 : 姓名 : " << A.Name" << A.Name << '\<< '\

n'n' << "<< " 電話號碼: 電話號碼: " << A.Phone" << A.Phone << '\<< '\

n'n' << "<< " 編號 : 編號 : " << A.Id" << A.Id << endl;<< endl; return;return; }}

Page 23: Chap 15  struct 與資料結構

2323/64/64

使用傳參照 使用傳參照 (pass by reference) (pass by reference) 改變改變 strstructuct 實例的內容實例的內容

例如:例如: ChangeName(Ea, “Jackson”);ChangeName(Ea, “Jackson”); 對應的「被呼叫函數」則定義成:對應的「被呼叫函數」則定義成: void ChangeName (void ChangeName (Employee&Employee& A, char New A, char NewName[])Name[])

{{

strcpy(strcpy(A.NameA.Name, NewName);, NewName);

return;return;

}}

Page 24: Chap 15  struct 與資料結構

2424/64/64

範例程式 檔案 範例程式 檔案 StructFnc.cppStructFnc.cpp

// StructFnc.cpp// StructFnc.cpp#include <iostream>#include <iostream>using namespace std;using namespace std;struct Employeestruct Employee{{

char Name[20];char Name[20];char Phone[10];char Phone[10];int Id; int Id;

};};

void void ShowMemberShowMember(Employee A)(Employee A){{ cout << "cout << " 資料的詳細內容是:資料的詳細內容是: \n" \n" << "<< " 姓名 : 姓名 : " << A.Name << '\n'" << A.Name << '\n' << "<< " 電話號碼: 電話號碼: " << A.Phone << '\n'" << A.Phone << '\n' << "<< " 編號 : 編號 : " << A.Id << endl; return;" << A.Id << endl; return;}}

Page 25: Chap 15  struct 與資料結構

2525/64/64

void void ChangeNameChangeName (Employee& A, char NewName[]) (Employee& A, char NewName[]) { strcpy(A.Name, NewName); return; }{ strcpy(A.Name, NewName); return; }

// ============= // ============= 主程式 主程式 ================================================int main()int main(){{ Employee Ea = {"Ann", "02384125", 105};Employee Ea = {"Ann", "02384125", 105}; Employee Eb = {"Joanne", "03544132", 106};Employee Eb = {"Joanne", "03544132", 106}; ShowMemberShowMember(Ea);(Ea); ShowMemberShowMember(Eb);(Eb); ChangeNameChangeName(Ea, "Jackson");(Ea, "Jackson"); cout << "cout << " 執行 執行 ChangeName() ChangeName() 後:後: \n";\n"; ShowMemberShowMember(Ea);(Ea); return 0;return 0;}}

Page 26: Chap 15  struct 與資料結構

2626/64/64

執行結果 執行結果

資料的詳細內容是:姓名 : Ann電話號碼: 02384125編號 : 105資料的詳細內容是:姓名 : Joanne電話號碼: 03544132編號 : 106執行 ChangeName() 後:資料的詳細內容是:姓名 : Jackson電話號碼: 02384125編號 : 105

Page 27: Chap 15  struct 與資料結構

2727/64/64

使用指標改變使用指標改變 structstruct 實例的內容實例的內容

使用使用傳址傳址 (pass-by-address) (pass-by-address) 來達到使用參照來達到使用參照的目的:的目的:

ChangeId(&Ea, 00128);ChangeId(&Ea, 00128); 「被呼叫函數」則定義為「被呼叫函數」則定義為 void ChangeId(Employee* pE, int NewId)void ChangeId(Employee* pE, int NewId) {{ (*pE).Id=NewId;(*pE).Id=NewId; return;return; }}

Page 28: Chap 15  struct 與資料結構

2828/64/64

pEpE 與與 EaEa 之間的關係之間的關係

pE

Name Phone Id

Ea

Page 29: Chap 15  struct 與資料結構

2929/64/64

C++ C++ 的具象指標符號 的具象指標符號 ->->

將 將 (*pE).Name(*pE).Name 寫成:寫成: pE->NamepE->Name 表示「由表示「由 pEpE 指向的指向的 structstruct 變數內的成員 變數內的成員 NamNam

ee 」。」。

Page 30: Chap 15  struct 與資料結構

3030/64/64

進一步改寫 進一步改寫 ChangeId()ChangeId()

void ChangeId(Employee* pE, int NewId)void ChangeId(Employee* pE, int NewId)

{{

pE->IdpE->Id = NewId; = NewId;

return;return;

}}

Page 31: Chap 15  struct 與資料結構

3131/64/64

範例程式 檔案 範例程式 檔案 StructFnc2.cpp StructFnc2.cpp

// StructFnc2.cpp// StructFnc2.cpp#include <iostream>#include <iostream>using namespace std;using namespace std;struct Employeestruct Employee{{

char Name[20];char Name[20];char Phone[10];char Phone[10];int Id; int Id;

};}; void ShowMember(void ShowMember(Employee AEmployee A)){{ cout << "cout << " 資料的詳細內容是:資料的詳細內容是: \n" \n" << "<< " 姓名 : 姓名 : " << " << A.NameA.Name << '\n' << '\n' << "<< " 電話號碼: 電話號碼: " << " << A.PhoneA.Phone << '\n' << '\n' << "<< " 編號 : 編號 : " << " << A.IdA.Id << endl; return; << endl; return;}}

Page 32: Chap 15  struct 與資料結構

3232/64/64

void ChangeName (void ChangeName (Employee& AEmployee& A, char NewName[]), char NewName[]) { strcpy({ strcpy(A.NameA.Name, NewName); return; }, NewName); return; }void ChangeId(void ChangeId(Employee* pE,Employee* pE, int NewId int NewId)) { { pE->IdpE->Id = NewId; return;} = NewId; return;}// ========= // ========= 主程式 主程式 ================================================int main()int main(){{ Employee Ea = {"Ann", "02384125", 105};Employee Ea = {"Ann", "02384125", 105}; Employee Eb = {"Joanne", "03544132", 106};Employee Eb = {"Joanne", "03544132", 106}; ShowMember(Ea);ShowMember(Ea); ShowMember(Eb);ShowMember(Eb); ChangeId(&ChangeId(&Ea, 208Ea, 208));; cout << "cout << " 執行 執行 ChangeId() ChangeId() 後:後: \n";\n"; ShowMember(Ea);ShowMember(Ea); return 0;return 0;} }

Page 33: Chap 15  struct 與資料結構

3333/64/64

執行結果執行結果

資料的詳細內容是:姓名 : Ann電話號碼: 02384125編號 : 105資料的詳細內容是:姓名 : Joanne電話號碼: 03544132編號 : 106執行 ChangeId() 後:資料的詳細內容是:姓名 : Ann電話號碼: 02384125編號 : 208

Page 34: Chap 15  struct 與資料結構

3434/64/64

structstruct 實例的動態宣告實例的動態宣告

亦即亦即 structstruct 實例的實例的動態記憶體配置動態記憶體配置 (dyna(dynamic memory allocation)mic memory allocation) 。。

下列敘述則可以在執行時才臨時決定陣下列敘述則可以在執行時才臨時決定陣列的大小:列的大小:

int Size;int Size;

cin >> Size;cin >> Size;

Employee* pE = new Employee[Size];Employee* pE = new Employee[Size];

Page 35: Chap 15  struct 與資料結構

3535/64/64

structstruct 實例的動態記憶體配置和回收實例的動態記憶體配置和回收

執行後會依指定的大小在記憶體的特殊區域,執行後會依指定的大小在記憶體的特殊區域,稱為稱為記憶堆記憶堆 (heap) (heap) 的地方,規劃出需要的的地方,規劃出需要的記憶空間,並把第一個變數的開頭位址存入記憶空間,並把第一個變數的開頭位址存入指標內。指標內。

如果此陣列不再需要,可以執行下列的敘述如果此陣列不再需要,可以執行下列的敘述回收記憶體空間:回收記憶體空間:

delete [] pE;delete [] pE;

Page 36: Chap 15  struct 與資料結構

3636/64/64

使用陣列下標或指標算數存取內部成員使用陣列下標或指標算數存取內部成員

例如,要取用第例如,要取用第 kk 個陣列元素內的成員個陣列元素內的成員IdId ,下述語法都是正確的:,下述語法都是正確的:

Labor[k].IdLabor[k].Id

(*(Labor + k)).Id(*(Labor + k)).Id

(Labor + k)->Id(Labor + k)->Id

pE[k].IdpE[k].Id

(*(pE + k)).Id(*(pE + k)).Id

(pE + k)->Id(pE + k)->Id

Page 37: Chap 15  struct 與資料結構

3737/64/64

範例程式範例程式 DynStruct.cppDynStruct.cpp

示範動態產生由示範動態產生由 structstruct 實例所構成的陣實例所構成的陣列,稱為列,稱為 EmployeeEmployee ,之完整語法,並,之完整語法,並在事後回收記憶空間。在事後回收記憶空間。

Page 38: Chap 15  struct 與資料結構

3838/64/64

範例程式 檔案 範例程式 檔案 DynStruct.cppDynStruct.cpp

// DynStruct.cpp// DynStruct.cpp#include <iostream>#include <iostream>using stdusing std :::: cin;cin;using stdusing std :::: cout;cout;struct Employeestruct Employee{{

char Name[20];char Name[20];char Phone[10];char Phone[10];int Id; int Id;

};};// --------- // --------- 主程式 主程式 ------------------------------------------------

Page 39: Chap 15  struct 與資料結構

3939/64/64

int main()int main()

{{

int Size;int Size;

cout << "cout << " 請輸入 請輸入 Employee Employee 的數目:的數目: \n";\n";

cin >> Size;cin >> Size;

EmployeeEmployee** pE = pE = newnew Employee Employee[[SizeSize]];;

delete []delete [] pE; pE;

return 0;return 0;

} }

Page 40: Chap 15  struct 與資料結構

4040/64/64

指標成員與資料結構指標成員與資料結構

structstruct 所宣告的資料型態可以使用「指標」做所宣告的資料型態可以使用「指標」做為成員。為成員。

指標成員可以指向自己所在的指標成員可以指向自己所在的 structstruct 資料型態,資料型態,稱為「稱為「自我參照自我參照」」 (auto-reference)(auto-reference) 。例如:。例如:

Struct DataStruct Data {{ int Id; int Id; Data* pD;Data* pD; };};

Page 41: Chap 15  struct 與資料結構

4141/64/64

串列 串列 (lists)(lists)

定義一串的定義一串的 DataData 變數:變數: Data D1, D2, D3;Data D1, D2, D3;

D1.pD = &D2;D1.pD = &D2;

D2.pD = &D3;D2.pD = &D3; 圖示如下:圖示如下:

串列最後一個元素內的指標值為串列最後一個元素內的指標值為 NULL (NULL ( 亦即 ‘亦即 ‘ \0’)\0’) ,,用來做為檢查串列是否「到此為止」的根據。用來做為檢查串列是否「到此為止」的根據。

Id Id Id

D1 D2 D3

\0

Page 42: Chap 15  struct 與資料結構

4242/64/64

串列 串列 (lists)(lists)

「「節點節點」」 (node): (node): 每一個用來儲存資料每一個用來儲存資料的元素第一個節點稱為的元素第一個節點稱為

「「開頭開頭」」 (head): (head): 第一個節點。第一個節點。 「「結尾結尾」」 (tail): (tail): 最後的節點。最後的節點。

Page 43: Chap 15  struct 與資料結構

4343/64/64

在陣列插入一個元素在陣列插入一個元素

int* V = new int [Size];int* V = new int [Size];

必需同時將必需同時將 V[1] V[1] 及其之後的所有元素往右移,及其之後的所有元素往右移,且無法應付陣列因長度增加而記憶空間可能且無法應付陣列因長度增加而記憶空間可能不足的問題。不足的問題。

18 21 30 \0

V[0] V[1] V[2] V[3] V[4]

V

Page 44: Chap 15  struct 與資料結構

4444/64/64

「串列」可以帶來的便利「串列」可以帶來的便利

使用使用串列串列 (linked list) (linked list) 可以較有效率地可以較有效率地完成元素增刪的動作。完成元素增刪的動作。

設想原先有設想原先有 A, B, C A, B, C 三個元素串接在一三個元素串接在一起形成一個串列:起形成一個串列:

A

\0

B C

21 18 30 \0

A B C

21 20

D

30 18 \0

Page 45: Chap 15  struct 與資料結構

4545/64/64

一個串列的範例一個串列的範例

假設使用假設使用 structstruct 宣告了一個名叫 宣告了一個名叫 ElemeElement nt 的自訂資料形態:的自訂資料形態:

struct Elementstruct Element

{{

int Value; int Value;

Element* Next; Element* Next;

};};

Page 46: Chap 15  struct 與資料結構

4646/64/64

動態產生任意數目的動態產生任意數目的 Element (Element ( 各實例的各實例的值在此為值在此為 0, 2, 4, 6, …)0, 2, 4, 6, …) ::

cout << "cout << " 請輸入 請輸入 Element Element 的數目:的數目: \n";\n";

cin >> Size;cin >> Size;

Element* pE = Element* pE = newnew Element[Size]; Element[Size];

for (int i=0; i<(Size-1); i++)for (int i=0; i<(Size-1); i++)

pE[i].Next = pE + i +1;pE[i].Next = pE + i +1;

pE[Size-1].Next = NULL;pE[Size-1].Next = NULL;

for (int i=0; i<(Size); i++)for (int i=0; i<(Size); i++)

pE[i].Value = i*2;pE[i].Value = i*2;

Page 47: Chap 15  struct 與資料結構

4747/64/64

顯示現有串列元素顯示現有串列元素

Element* pShow; Element* pShow;

for (pShow = pE; pShow != NULL; pShow=pShow->Next)for (pShow = pE; pShow != NULL; pShow=pShow->Next)

cout << pShow->Value << ' ';cout << pShow->Value << ' ';

不斷更換指標使它指向下一個元素的位址。不斷更換指標使它指向下一個元素的位址。

Page 48: Chap 15  struct 與資料結構

4848/64/64

以以 whilewhile 迴圈顯示現有串列元素迴圈顯示現有串列元素

Element* pShow=pE; Element* pShow=pE;

while (pShow != NULL)while (pShow != NULL)

{{

cout << pShow->Value << ' ';cout << pShow->Value << ' ';

pShow = pShow->Next;pShow = pShow->Next;

}}

Page 49: Chap 15  struct 與資料結構

4949/64/64

將顯示串列內容的功能封裝到函數中將顯示串列內容的功能封裝到函數中

void ShowElement(Element* pShow)void ShowElement(Element* pShow)

{{

while (pShow != NULL)while (pShow != NULL)

{{

cout << pShow->Value << ' ';cout << pShow->Value << ' ';

pShow = pShow->Next;pShow = pShow->Next;

}}

}}

Page 50: Chap 15  struct 與資料結構

5050/64/64

範例程式 檔案 範例程式 檔案 ListStruct.cppListStruct.cpp

// ListStruct.cpp// ListStruct.cpp#include <iostream>#include <iostream>using namespace std;using namespace std;struct Elementstruct Element{{ int Value; int Value; Element* Next; Element* Next; };};void ShowElement(Element* pShow)void ShowElement(Element* pShow){{ while (pShow != NULL)while (pShow != NULL) {{ cout << pShow->Value << ' ';cout << pShow->Value << ' '; pShow = pShow->Next;pShow = pShow->Next; }}}}

Page 51: Chap 15  struct 與資料結構

5151/64/64

// ---// --- 主程式主程式 ------------------------------------------------int main()int main(){{ int Size;int Size; cout << "cout << " 請輸入 請輸入 Element Element 的數目的數目 :\n";:\n"; cin >> Size;cin >> Size; ElementElement** pE = pE = newnew Element Element[[SizeSize]];; for (int i=0; i<(Size-1); i++)for (int i=0; i<(Size-1); i++) pE[i].Next = pE + i +1;pE[i].Next = pE + i +1; pE[Size-1].Next = NULL;pE[Size-1].Next = NULL; for (int i=0; i<(Size); i++)for (int i=0; i<(Size); i++) pE[i].Value = i*2; pE[i].Value = i*2; cout << "Element cout << "Element 的內容是的內容是 :\n";:\n"; ShowElement(pE);ShowElement(pE); delete [] pE;delete [] pE; return 0;return 0;} }

Page 52: Chap 15  struct 與資料結構

5252/64/64

執行結果執行結果

請輸入 Element 的數目:5Element 的內容是:0 2 4 6 8

Page 53: Chap 15  struct 與資料結構

5353/64/64

雙向鏈結串列 雙向鏈結串列 (doubly- linked list)(doubly- linked list)

能夠自由在串列中往返尋找。能夠自由在串列中往返尋找。 每個節點內都含有兩個指標,分別指向每個節點內都含有兩個指標,分別指向下一個節點及上一個節點。下一個節點及上一個節點。 Head

\0

Node1 Node2

Tail

\0

Page 54: Chap 15  struct 與資料結構

5454/64/64

「雙向鏈結串列」的宣告「雙向鏈結串列」的宣告

struct struct NodeNode

{{

int Value;int Value;

Node*Node* Previous; Previous;

Node*Node* Next; Next;

};};

Page 55: Chap 15  struct 與資料結構

5555/64/64

樹狀結構 樹狀結構 (tree)(tree)

二維結構。二維結構。 開頭的節點稱為「開頭的節點稱為「根根」」 (root)(root) 。。 「「層層」」 (layer): (layer): 與根的距離相同的所有與根的距離相同的所有節點。節點。

「「葉葉」」 (leaves): (leaves): 不再指向下一層節點的不再指向下一層節點的所有節點。所有節點。

Page 56: Chap 15  struct 與資料結構

5656/64/64

二元樹 二元樹 (binary tree)(binary tree)

由於每個節點都只有兩個指標向下一層的兩個節點,由於每個節點都只有兩個指標向下一層的兩個節點,形成一個「品」字型的局部結構,因此稱為「二元形成一個「品」字型的局部結構,因此稱為「二元樹」。樹」。

\0 \0 \0

第 0 層

root

\0 \0

\0 \0 \0 \0

leaf

leaf leaf leaf

第 1 層

第 2 層

第 3 層

Page 57: Chap 15  struct 與資料結構

5757/64/64

unionunion 資料型態資料型態 可以在其內擁有多種資料型態,但一次只能有一種資可以在其內擁有多種資料型態,但一次只能有一種資

料型態。例如:料型態。例如: unionunion Data Data {{ float FloatValue;float FloatValue; double DoubleValue;double DoubleValue; char CharValue;char CharValue; int IntValue;int IntValue; }};; Data D1;Data D1; 每個每個 DataData 變數擁有的記憶空間由佔有最大空間的成變數擁有的記憶空間由佔有最大空間的成

員 員 (( 此例為此例為 D1.DoubleValue) D1.DoubleValue) 所決定。使用所決定。使用 unionunion 的的目的在於節省記憶體。目的在於節省記憶體。

Page 58: Chap 15  struct 與資料結構

5858/64/64

enumenum 資料型態資料型態

enumenum 是是 enumerate enumerate (( 列舉列舉 ) ) 的簡寫。的簡寫。 由由 enumenum 所定義的任何所定義的任何實例實例 (instance) (instance) 只能擁有只能擁有當初當初 enumenum 宣告時所列舉的值之一。例如:宣告時所列舉的值之一。例如: enumenum Direction {Up, Down, Left, Right}; Direction {Up, Down, Left, Right};

Direction x;Direction x; 我們只能把這四種可能的值指定給我們只能把這四種可能的值指定給 xx 。例如:。例如: x = Right;x = Right; 在電腦內部 在電腦內部 {Up, Down, Left, Right} {Up, Down, Left, Right} 分別和 分別和 {0, {0,

1, 2, 3} 1, 2, 3} 比對。比對。

Page 59: Chap 15  struct 與資料結構

5959/64/64

可以在宣告可以在宣告 enum enum 時給予各成員確定的數時給予各成員確定的數值值

例如:例如: enum Check {Error = -1, Suspicious, enum Check {Error = -1, Suspicious, Acceptable = 5, OK = 10};Acceptable = 5, OK = 10};

沒有特別指定的的值為其前一個成員 沒有特別指定的的值為其前一個成員 (( 亦即亦即Error) Error) 的值加的值加 11 ,,

因此因此 suspicioussuspicious 的內值為 –的內值為 – 1 + 1 = 01 + 1 = 0 。。

Page 60: Chap 15  struct 與資料結構

6060/64/64

enumenum 資料型態資料型態 使用使用 enumenum 型態的目的是為了增進程式的可讀性,常型態的目的是為了增進程式的可讀性,常

與與 switchswitch 和和 ifif 等判斷式結合使用。例如:等判斷式結合使用。例如: int N;int N; cin >> N;cin >> N; switch (N)switch (N) {{ case case UpUp :: cout << “Moving Up!\n”; cout << “Moving Up!\n”; break;break; case case DownDown :: cout << “Moving Down!\n”; cout << “Moving Down!\n”; break;break; case case LeftLeft :: cout << “Moving Left!\n”; cout << “Moving Left!\n”; break;break;

Page 61: Chap 15  struct 與資料結構

6161/64/64

case case RightRight :: cout << “Moving Right!\n”; cout << “Moving Right!\n”;

break;break;

defaultdefault :: cout << “Static\n”;cout << “Static\n”;

}}

Page 62: Chap 15  struct 與資料結構

6262/64/64

範例程式 檔案 範例程式 檔案 TestEnum.cppTestEnum.cpp

// TestEnum.cpp// TestEnum.cpp#include <iostream>#include <iostream>using namespace std;using namespace std;enum Direction {Up, Down, Left, Right};enum Direction {Up, Down, Left, Right};// -------- // -------- 主程式 主程式 ------------------------------------------------int main()int main(){{ int int NN;; cout << "cout << " 請輸入期望的運動方向請輸入期望的運動方向 \n";\n"; cout << "(0=Up, 1=Down, 2=Left, 3=Right):\n";cout << "(0=Up, 1=Down, 2=Left, 3=Right):\n"; cin >> cin >> NN;; switch (switch (NN)) {{ case case UpUp:: cout << "Moving Up!\n"; cout << "Moving Up!\n"; break;break;

Page 63: Chap 15  struct 與資料結構

6363/64/64

case case DownDown:: cout << "Moving Down!\n"; cout << "Moving Down!\n"; break;break; case case LeftLeft:: cout << "Moving Left!\n"; cout << "Moving Left!\n"; break;break; case case RightRight:: cout << "Moving Right!\n"; cout << "Moving Right!\n"; break;break; defaultdefault:: cout << "Static\n";cout << "Static\n"; }} return 0;return 0;} }

Page 64: Chap 15  struct 與資料結構

6464/64/64

執行結果 執行結果

請輸入期望的運動方向(0=Up, 1=Down, 2=Left, 3=Right) :2

Moving Left!