陣列與鏈結串列 Array and Linked List -...
Transcript of 陣列與鏈結串列 Array and Linked List -...
講師:洪安
陣列與鏈結串列Array and Linked List
1
大綱
2
結構陣列
鏈結串列
單向鏈結串列之資料型態
單向鏈結串列之基本運算
課堂練習
優點 使用容易
缺點 刪除與插入造成資料移動頻繁
浪費不必要之記憶體
class student{
int math;int english;int computer;
};
int main(){
student s[5];return 0;
}
結構陣列
3
math
english
computer
s
student student student student student
[0] [1] [2] [3] [4]
動態記憶體配置 (1/2) new運算子會配置一個int所需要的空間,並傳回該空
間的位址,所以您使用指標ptr來儲存這個位址 int *ptr = new int;
如果要在配置完成後指定儲存值,則可以如此宣告 int *ptr = new int(100);
4
#include <iostream> using namespace std;int main() {
int *ptr = new int(100); cout << "空間位置:" << ptr << endl;cout << "空間儲存值:" << *ptr << endl;
*ptr = 200; cout << "空間位置:" << ptr << endl;cout << "空間儲存值:" << *ptr << endl;delete ptr;
return 0; }
4
動態記憶體配置 (2/2) 動態配置陣列空間 int *arr = new int[1000];
歸還配置陣列空間給記憶體 delete [] arr;
5
#include <iostream>using namespace std; int main() {
int size = 0; cout << "請輸入陣列長度:"; cin >> size;
int *arr = new int[size]; cout << "指定元素值:" << endl; for(int i = 0; i < size; i++) {
cout << "arr[" << i << "] = "; cin >> *(arr+i);
}
cout << "顯示元素值:" << endl; for(i = 0; i < size; i++) {
cout << "arr[" << i << "] = " << *(arr+i) << endl; } delete [] arr; return 0;
}
5
複習:動態記憶體配置
動態記憶體配置則是:
當程式執行到一半, 發現它需要一塊記憶體空間來存放資料, 才向系統索取一塊記憶體空間
當此記憶體空間用不到時, 也可隨時將之釋放供其它程式使用
動態記憶體配置的特色:有需要, 才配置!
6
大綱
結構陣列
鏈結串列
單向鏈結串列之資料型態
單向鏈結串列之基本運算
課堂練習
7
鏈結串列 Linked List
定義
由一組節點(node)所構成
各節點之間並不一定占用連續的Memory空間
各節點的型態不一定相同
插入節點、刪除節點方便 因為只改變指標
僅支援循序存取,不支援隨機存取
可任意(動態)增加、刪除空間
8
陣列與鏈結串列比較陣列 鏈結串列
占用連續的記憶體空間 可以非連續
各元素型態皆相同 各節點型態不必一定相同
不支援串列之共享 支援
插入、刪除元素麻煩(因為需挪移元素)
方便
無法動態增加、刪除空間 可以
可支援循序及隨機存取 僅支援循序存取
可靠度高 低,因為指標斷裂,資料就遺失
循序存取速度快 慢,因為必須先讀取指標9
靜態與動態結構
class node{
資料型態變數名稱; //如 : int data;
node *next;};node c;node *head;c.next = NULL;head = NULL;
head = new node;head->next = NULL;
(new)
node
資料
NULLnode *
資料型態 變數名稱
next
c
node
資料
NULL
資料型態 變數名稱
next
node *
head
node *
10
鏈結串列節點
節點:鏈結串列中最基本的單位
節點
下一個節點
資料
物件指標
節點 = 資料+ 物件指標
11
定義鏈結串列節點結構
鏈結串列透過儲存元素在記憶體之位址為指標(Pointer)或鏈結(Link)取得下一個節點
定義節點結構
node
class node{
資料型態變數名稱; //如 : int data;
node *next;};
資料
下一個節點node *
資料型態 變數名稱
next
12
單向鏈結串列
單向鏈結串列之類別如下圖所示
head:指向串列前端之指標
tail:指向串列尾端之指標
…鏈結起點 鏈結終點
head tail
NULL
13
走訪鏈結串列 從head開始
依序存取節點中的next指標
直到存取到NULL為止
範例:print()
走訪鏈結串列並輸出每個節點之data值
14
小練習 (建立鏈結串列節點)
定義一個鏈結串列節點類別如下圖所示,並使用head與tail指標指向動態配置之節點
data
next
(new)
node
10
NULLnode *
int
node *
head
node *
tail
15
1. 請定義Node類別,並設定LinkedList類別為其夥伴(friend class LinkedList;)
2. 請定義LinkedList類別,類別資料成員包含 head 與 tail
3. 請實作建構函數,內容包含新增一個節點,設定data為10 ,設定next為NULL,並讓head和tail指到此新增節點
4. 請實作print()函數
答案在7-15.cpp,請先自己試試看唷
大綱
結構陣列
鏈結串列
單向鏈結串列之資料型態
單向鏈結串列之基本運算
課堂練習
16
新增節點
動態配置一節點之記憶體
node *LinkedList::getnode () /* 此函數產生一個新節點 */
{
node *p;
p = new node;
if ( p == NULL)
{
cout << "記憶體不足" << endl;
exit(1);
}
return(p);
}
17
釋放節點
歸還一個節點之記憶體
void LinkedList::freenode (node *p)
/* 此函數將節點還給記憶體 */
{
delete p;
}
18
由鏈結串列加入一個節點
一個節點之插入有三種情況:
節點加於第一個節點之前
節點加於最後一個節點之後
加於節點中間任何一個位置
插入節點
head
… NULL
ptr
new tail
head
… NULL
ptr
tail new
new
… NULL
ptr
head tail
19
插入節點
加於節點中間任何一個位置new
… NULL
ptr
head tail
×
new
… NULL
ptr
head tail
(1)
(2)
(3)
(4)
20
插入節點void LinkedList::insert_node(Node *ptr, int value) {
Node *new_node = getnode();new_node -> data = value;new_node -> next = NULL;
if (ptr == NULL) { //加在串列首new_node -> next = head;head = new_node;
}else if (ptr == tail){ //加在串列尾 等同於 ptr->next == NULL;
ptr -> next = new_node;tail = tail -> next; //等同於 tail = new_node;
}else { //加在串列中間
new_node -> next = ptr -> next;ptr -> next = new_node;
}}
21
插入節點前的動作 找到插入的位置指標,傳給 insert_node(node
*ptr, int value)
22
void LinkedList::insert(int value)
{
if(head==NULL) //串列為空{
head = getnode();
head->data=value;
head->next=NULL;
tail = head;
}
else //串列不為空{
insert_node(tail, value);
}
cout << "Insert Successful!" << endl;
}
小練習 (插入鏈結串列節點)
延續上一個練習
修改建構函數為設定head, tail為NULL
寫一個使用者介面,輸入i,接著輸入一個數字value,可插入一筆資料節點中之data為value於串列最後 (insert, insert_node functions)
輸入其他則印出串列內容並結束
建立一個鏈結串列如下圖所示:
data
next
(new)
node
10
node *
int
node *
head
node *
tail
(new)
node
20
(new)
node
30
NULL23
答案在7-23.cpp,請先自己試試看唷
刪除節點
由鏈結串列中刪除一個節點
一個節點之刪除有三種情況:
刪除第一個節點
刪除最後一個節點
刪除中間任何一個節點
head
… NULL
ptr
tail
head
… NULL
tail
previous
… NULL
ptr
head tail
NULL
24
刪除節點
刪除中間任何一個節點
… NULL
ptr
head tail(1)
previous
… NULL
ptr
head tail
previous
×
(2)25
刪除節點
26
void LinkedList::remove_node(Node *ptr) {if (ptr == head) { /* 第一種情況: 刪除第一個節點 */
head = head -> next;}else {
//尋找ptr的前一個節點Node *prev = head; /* 指向前一節點 */while (prev -> next != ptr) {
prev = prev -> next; }/* 第二種情況: 刪除最後一個節點 */if (ptr == tail) { /* 最後一個節點 */
prev -> next = NULL;tail = prev;
}/* 第三種情況: 刪除中間節點 */else {
prev -> next = ptr ->next; /* 圖(3)之步驟(1) */}
}freenode(ptr); /* 此函數將節點歸還給記憶體 */
}
找到刪除節點的位置
27
小練習 (刪除鏈結串列節點)
延續上一個練習
寫一個使用者介面,輸入d,接著輸入一個數字value,可將一筆資料節點中之data與value相同者刪除(假設輸入之value不會重覆)
28 答案在7-28.cpp,請先自己試試看唷
尋找節點
走訪串列,尋找輸入和資料相同的節點
29
小練習 (尋找鏈結串列節點)
延續上一個練習
寫一個使用者介面,輸入f,接著輸入一個數字value,可將一筆資料節點中之data與value相同者印出資料
30答案在7_LinkedList.cpp,請先自己試試看唷
鏈結串列長度
計算鏈結串列之長度
int LinkedList::length () /* 此函數計算節點之鏈結長度*/{
int num=0;node *q = head;while (q != NULL) {
num ++;q = q->next;
}return(num);
}31