プログラミング演習Ⅲ Linked List
P. Ravindra S. De Silva
e-Mail:
Page 2
連結リストとは ?
A B C D ∅
一つひとつの要素がその前後の要素との参照関係をもつデータ構造
連結リストを使用する利点
-
通常の配列はサイズが固定されている:
データの挿入や削除をしたい ときはデータを移動させる必要がある連結リストならば必要なサイズ分だけ追加することができる
:
挿入や削 除をしてもデータを移動させる必要はない単方向リスト
単方向リストは、連続ノード からなるデータ構造の基本的 な概念である
各ノードは次を格納する
–
要素–
次のノードへのリンク次
要素 ノード
A B C D ∅
Page 4
4
連結リストの実装
任意のデータフィールド群を持ち、1
つか2
つの参照(リンク)により次(お よび前)のノードを指している。struct list {
int data;
struct list *next;
}
次を参照するポインタをリンクと呼ぶ。どの構造体も後続の領域へ導くリ ンクでつながる。この後続を参照するポインタは、メモリ内のそれぞれの 場所を示すアドレス、または特別な値NULL
を含む。data next
例
struct list {
int data;
struct list *next;
}
struct list a, b, c;
a.data = 1;
b.data = 2;
c.data = 3;
a.next = b.next = c.next = NULL;
b
a c
NULL
NULL 2 3 NULL
1
Page 6
例(つづき)
struct list {
int data;
struct list *next;
}
struct list a, b, c;
a.data = 1;
b.data = 2;
c.data = 3;
a.next = b.next = c.next = NULL;
a.next = &b;
b.next = &c;
b
a c
3 2
1
動的メモリ操作
struct node{
int data;
struct node *next;
};
struct node *ptr;
ptr = (struct node *) /*type casting */
malloc(sizeof(struct node));
data next ptr
Page 8
Free 操作
関数free
はメモリを解放する- 換言すると、メモリをシステムに返すことで、将 来的にそのメモリを解放することができるfree(ptr);
ptr
?
連結リストのノード – 例
3
つのデータ領域をもったノード:struct student{
char name[20];
int id;
double grdPts;
struct student *next_student;
}
Name id grdPts next_student
Page 10
連結リストの基本的な操作
ノードを追加する
ノードを削除する
ノードを検索する
リストの走査 : カウント処理や統計的な処理に便利空の連結リストにノードを追加する
処理前
:
pNew -> next = pHead; //
リンクを設定NULL pHead = pNew;// point list to first node
処理後
:
39 pNew
pHead
pPre
39 pNew
pHead
Page 12
連結リストの先頭にノードを追加する
処理前
:
処理後
:
39 pNew
pHead
pPre
75 124
39 pNew
pHead
pPre
75 124
pNew -> next = pHead;
pHead = pNew; //
先頭ノードのリストを参照連結リストの中間にノードを追加する
処理前 :
pNew -> next = pPre -> next;
pPre -> next = pNew;
処理後 :
64 pNew
pPre
55 124
64 pNew
55 124
Page 14
連結リストの終端にノードを追加する
処理前 : pNew -> next = NULL;
pPre -> next = pNew;
処理後 :
144 pNew
pPre
55 124
pNew 144
pPre
55 124
連結リストにノードを挿入する
先 頭(pHead)
と 前(pPre)
の ポ イ ンタ を与 え て、 データ が 挿 入 さ れ る(item).
新しいノードのためのメモリが確保され
(pNew)
、リンクが適切につながる。//連結リストにノードを挿入する struct node *pNew;
pNew = (struct node *) malloc(sizeof(struct node));
pNew -> data = item;
if (pPre == NULL){
//先頭ノードの前に追加する もしくか 空の場合 pNew -> next = pHead;
pHead = pNew;
}
else {
//中間か終端に追加する
pNew -> next = pPre -> next;
Page 16
連結リストからノードを削除する
いくつかのリンクを変更しリストからノードを理論的に取り除くことで、リ ストから物理的にノードを削除することができる
リスト中の任意のノードを削除することができる。リスト中のノードを削除 して空のリストとなった場合は、先頭ポインタはヌルに設定される。
理論的にノードを削除する:
–
消したいノード(pCur)
とその前にあるノード(pPre)
を考える.
–
前のノードのリンクの指し示すノード(pPre->next)
を,消したいノードの次の ノード(pCur -> next)
にする.– free
関数を使って消したノードの領域を解放する.連結リストから一番目のノードを削除する
処理前
: pHead = pCur -> next;
free(pCur);
処理後
:
pHead
pPre
75 124
pCur
pHead
pPre
Recycled 124
pCur
Page 18
連結リストからノードを削除する – 一般的な場合
処理前
: pPre -> next = pCur -> next;
free(pCur);
処理後
:
75 96 124
pPre pCur
75 Recycled 124
pPre pCur
連結リストからノードを削除する
ノードの先頭(pHead)
,消したいノード(pCur),
消したいノードの一つ前のノード
(pPre)
を用意する.pCur
を消し,pCur
の為に確保された領域を解放するという処理は,以下のようになる.
//
連結リストからノードを削除するif (pPre == NULL)
//
リストの最初のノードだった場合の削除pHead = pCur -> next;
else
//
リストの最初のノード以外の場合の削除pPre -> next = pCur -> next;
free(pCur).
Page 20
連結リストの検索
連結リストの挿入や削除の操作はどちらも,特定の,挿入先のノードや消したい データに一致するノードを検索しなければならない.//連結リストからノードを検索する pPre = NULL;
pCur = pHead;
//目的の値が見つかるまで、あるいはデータの終端にたどり着くまで繰り返す while (pCur != NULL && pCur -> data != target) {
pPre = pCur;
pCur = pCur -> next;
}
//目的の値が見つかったら、あるいはデータの終端に来たらどうするか if (pCur != NULL)
found = 1;
else
found = 0;
連結リストの走査
リストの走査はリストにある全てのデータを処理する.したがって,全て のノードにあるデータは処理される.//
連結リストの走査Struct node *pWalker;
pWalker = pHead;
printf(“
リストに含まれているのは:¥n”);
while (pWalker != NULL){
printf(“%d ”, pWalker -> data);
pWalker = pWalker -> next;
}
Page 22
応用
多項式
一つの連結リストで表される多項式 以下の多項式を表現したい
A x ( ) = a m − 1 x e
m−1+ a m − 2 x e
m−2+ + ... a x 0 e
0• 以下のような 0 でない係数 a
iと負でない乗数 e
iの場合 … e
m-1> e
m-2> … > e
1> e
0≧ 0.
– それぞれの項を係数と乗数,次の項へのポインタを含むノード
として表す.
Page 24
宣言
typedef struct poly_node *poly_pointer;
typedef struct poly_node { int coef;
int expon;
poly_pointer link;
};
poly_pointer a, b, c;
coef expon link
A x ( ) = a m − 1 x e
m−1+ a m − 2 x e
m−2+ + ... a x 0 e
0例:多項式を表現する
a = 3 x 14 + 2 x 8 + 1
3 14 2 8 1 0
a null
b = 8 x 14 − 3 x 10 + 10 x 6
Page 26
多項式の加算
二つの多項式を足すには,多項式aと多項式bで示されているノー ドで始まるそれぞれの項を調べる.
二つの項の乗数が等しい場合,二つの係数を足し,結果の多項 式に新しい項を作る.
今調べているaの項の乗数が,bの項の乗数よりも少ない場合,b
の項を複製し,結果の多項式に加える.そして,bの項を次の項へ
進める.(a->expon > b->expon の場合も,同様に行う.)
例:多項式の加算
(a) a->expon == b->expon
3 14 2 8 1 0
a
8 14 -3 10 10 6
b 11 14
d a->expon == b->expon
Page 28
例:多項式の加算
(b) a->expon < b->expon
3 14 2 8 1 0
a
8 14 -3 10 10 6
b 11 14
d -3 10
a->expon < b->expon
例:多項式の加算
(c) a->expon > b->expon
3 14 2 8 1 0
a
8 14 -3 10 10 6
b
11 14 -3 10 2 8
Page 30
サンプルコード
Program 4.10 : 2つの多項式を加算する
poly_pointer padd(poly_pointer a, poly_pointer b) {
poly_pointer front, rear, temp;
int sum;
rear =(poly_pointer)malloc(sizeof(poly_node));
if (IS_FULL(rear)) {
fprintf(stderr, “The memory is full¥n”);
exit(1);
}
front = rear;
while (a && b) {
switch (COMPARE(a->expon, b->expon)) {
サンプルコード(つづき)
case -1: /* a->expon < b->expon */
attach(b->coef, b->expon, &rear);
b= b->link;
break;
case 0: /* a->expon == b->expon */
sum = a->coef + b->coef;
if (sum) attach(sum,a->expon,&rear);
a = a->link; b = b->link;
break;
case 1: /* a->expon > b->expon */
attach(a->coef, a->expon, &rear);
a = a->link;
} }
for (; a; a = a->link) attach(a->coef, a->expon, &rear);
for (; b; b=b->link)attach(b->coef, b->expon, &rear);
rear->link = NULL;
temp = front; front = front->link; free(temp);
return front;
Page 32
サンプルコード
for (; a; a = a->link) attach(a->coef, a->expon, &rear);
for (; b; b=b->link)attach(b->coef, b->expon, &rear);
rear->link = NULL;
temp = front; front = front->link; free(temp);
return front;
}