• 検索結果がありません。

アルゴリズムとデータ構造 補足資料 5-2 「サンプルプログラム setop.c 」

N/A
N/A
Protected

Academic year: 2021

シェア "アルゴリズムとデータ構造 補足資料 5-2 「サンプルプログラム setop.c 」"

Copied!
52
0
0

読み込み中.... (全文を見る)

全文

(1)

アルゴリズムとデータ構造 補足資料 5-2

「サンプルプログラム setop.c 」

横浜国立大学

理工学部

数物・電子情報系学科

富井尚志

(2)

集合の表現

• A = { 1, 2, 4, 5}

A は、要素 1, 2, 4, 5をもつ集合

表現方法1:ビット列の位置で表す

位置=要素

その位置のビットが1(True)→その要素が集合Aに存在する その位置のビットが0(False)→その要素は集合Aには存在しない 位置:要素 12345678

ビット   11011000

       → 1101100 ≡ A = { 1, 2, 4, 5} とみなす

表現方法2:配列に代入する

添え字は特に意味を持たない

要素がこれ以上存在しないこと(終わり)を示す必要がある A[N]={1,2,4,5,-1}

「表現」=「みなす」(データ構造を定義した人=使う人、が決める)

どちらの方法がよい、という議論はこの際しない。

(3)

サンプルプログラム: setop.c

集合の印刷 (一部抜粋)

配列名=配列へのポインタ に注目

関数 printset からは、 main 関数のブロック内だけで有効な

配列変数 s[MAX] にポインタを使って参照することができる。

printset の仮引数 a は、 int 型配列への「ポインタ」変数。

printset 内では、配列 a として扱う(配列 s を参照する)ことができる。

配列 s の実体は、 main 関数にある。

(4)

/****************************************************************

アルゴリズムとデータ構造 サンプルプログラム setop.c <<集合演算>>

copyright (c) 1995,96,97 T.Mori <[email protected]>

****************************************************************/

#include <stdio.h>

#define MAX 100 /* MAX は 配列の最大値要素数 */

#define EOSET -1 /* 集合の終りを表すマーク */

#define NOTMEMBER -2 /* 集合の要素がないことを表すマーク */

#define TRUE 1 /* */

#define FALSE 0 /* */

void rmdup(int a[ ]);

void printset(int a[ ]);

void set_intersec(int a[ ],int b[ ], int c[ ]);

void set_union(int a[ ],int b[ ], int c[ ]);

void set_difference(int a[ ], int b[ ], int c[ ]);

main() {

int s[MAX] = {3,4,2,6,2,9,9,9,1,5,2,9,6,8,6,EOSET};

int t[MAX] = {1,2,3,4, 7,8,9,10,EOSET};

int u[MAX] = {1, 3,4,5,6,7, 9, EOSET};

int v[MAX];

printf("s[]: ");

printset(s);

/* 配列の名前だけを指定すると配列自身を指定したことになる.

* 正確にいうと,配列が配置されている記憶領域の先頭の番地 * を表す.

*/

/* */

return 0;

}

/* 集合の印刷 */

void

printset(int a[]) {

int i;

for (i = 0; a[i] != EOSET; i++) { printf("%d ",a[i]);

}

printf("\n");

}

(5)

アドレス ( 32bit

中身( 1記憶単位は 8bit

… …

0x 40ea 0800

0000 0000

0x 40ea 0801 0000 0000

0x 40ea 0802 0000 0000

0x 40ea 0803 0000 0011

0x 40ea 0804 0000 0000

0x 40ea 0805 0000 0000

0x 40ea 0806 0000 0000

0x 40ea 0807 0000 0100

0x 40ea 0808 0000 0000

0x 40ea 0809 0000 0000

0x 40ea 080a 0000 0000

0x 40ea 080b 0000 0010

0x 40ea 080c 0000 0000

0x 40ea 080d 0000 0000

0x 40ea 080e 0000 0000

0x 40ea 080f 0000 0110

0x 40ea 0810 0000 0000

… …

s[0]

s[1]

s[2]

s[3]

s[4]

s

(s+1)

(s+2)

(s+3)

(s+4)

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

配列 s の実体はメモリの中に、

アドレスを伴なって存在する。

配列名 s は、 s の先頭アドレスを 示す。

int s[100];

… f(s);

void f(int a[]) {

printf(“a[0]=%d, a[1]=%d\n”, a[0], a[1]);

}

0x 40ea 0800 a

3, 4

と表示される:

関数 f からは、 a の名前で実体を参照する。

(6)

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) { printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

printf("s[]: ");

printset(s);

return 0;

int main( void)

変数 int s[MAX]

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

変数 int i

(7)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]:

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

(8)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]:

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

(9)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]:

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

printset(40ea0800)

40ea0800

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) { printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

変数 int i

(10)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]:

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

printset(40ea0800)

40ea0800

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) { printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

変数 int i

値渡しによる 関数呼び出し Call by Value

ポインタによる参照 Reference

参照渡しによる 関数呼び出しに相当 Call by Reference

(11)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]:

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

printset(40ea0800)

40ea0800

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) { printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

0

変数 int i

(12)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]:

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

printset(40ea0800)

40ea0800

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) { printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

0

変数 int i

a[0]

(13)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]: 3

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

printset(40ea0800)

40ea0800

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) {

printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

0

変数 int i

a[0]

(14)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]: 3

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

printset(40ea0800)

40ea0800

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) { printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

1

変数 int i

(15)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]: 3

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

printset(40ea0800)

40ea0800

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) { printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

1

変数 int i

a[1]

(16)

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

s[]: 3 4

s[0] s[1] s[2] s[15] a[99]

3 4 2 … EOSET … …

s = 0x 40ea 0800

printset(40ea0800)

40ea0800

仮引数 int a[]

for (i = 0; a[i] != EOSET; i++) {

printf("%d ",a[i]);

}

printf("\n");

戻り値なし( void ) void printset( int a[] )

1

変数 int i

a[1]

(17)

サンプルプログラム: setop.c

集合の印刷 (一部抜粋)

配列名=配列へのポインタ に注目

関数 printset からは、 main 関数のブロック内だけで有効な

配列変数 s[MAX] にポインタを使って参照することができる。

printset の仮引数 a は、 int 型配列への「ポインタ」変数。

printset 内では、配列 a として扱う(配列 s を参照する)ことができる。

配列 s の実体は、 main 関数にある。

(18)

サンプルプログラム: setop.c

重複除去のアルゴリズム (一部抜粋)

配列名=配列へのポインタ に注目

関数 rmdup では、二つの添え字 i と j を使って

配列 a の2か所を参照する。

rmdup からは、配列名 a によって配列 s を参照している。

→main 関数内の s の内容が書き換えられる。

(19)

/****************************************************************

アルゴリズムとデータ構造 サンプルプログラム setop.c <<集合演算>>

copyright (c) 1995,96,97 T.Mori <[email protected]>

****************************************************************/

#include <stdio.h>

#define MAX 100 /* MAX は 配列の最大値要素数 */

#define EOSET -1 /* 集合の終りを表すマーク */

#define NOTMEMBER -2 /* 集合の要素がないことを表すマーク */

#define TRUE 1 /* */

#define FALSE 0 /* */

void rmdup(int a[ ]);

void printset(int a[ ]);

void set_intersec(int a[ ],int b[ ], int c[ ]);

void set_union(int a[ ],int b[ ], int c[ ]);

void set_difference(int a[ ], int b[ ], int c[ ]);

main() {

int s[MAX] = {3,4,2,6,2,9,9,9,1,5,2,9,6,8,6,EOSET};

int t[MAX] = {1,2,3,4, 7,8,9,10,EOSET};

int u[MAX] = {1, 3,4,5,6,7, 9, EOSET};

int v[MAX];

/* */

/* 重複除去 */

printf("rmdup(s)\n");

rmdup(s);

printf("s[]: ");

printset(s);

/* */

return 0;

}

/* 重複を除去する関数 */

void

rmdup(int a[]) {

int i,j,d;

/* 重複する要素にマークをつける */

for(i=0; a[i] != EOSET; i++)

for(j=i+1; a[j] != EOSET; j++) if (a[j] == a[i])

a[j] = NOTMEMBER;

/* マークのついた要素をつめるように配列を作り直す */

d = 0;

for(i=0; a[i] != EOSET; i++) if (a[i] == NOTMEMBER)

d++; /* 要素の移動距離を1だけ増やす */

else {

if (d > 0)

a[i-d] = a[i]; /* 距離 d だけ要素を前方に移動

*/

}

a[i-d] = a[i]; /* 配列の最後のマークも移動 */

}

(20)

仮引数 int a[]

for(i=0; a[i] != EOSET; i++) for(j=i+1; a[j] != EOSET; j++) if (a[j] == a[i])

a[j] = NOTMEMBER;

d = 0;

for(i=0; a[i] != EOSET; i++) if (a[i] == NOTMEMBER) d++;

else { if (d > 0) a[i-d] = a[i];

} a[i-d] = a[i];

戻り値なし( void ) void rmdup( int a[] )

printf("rmdup(s)\n");

rmdup(s);

printf("s[]: ");

printset(s);

return 0;

int main( void)

変数 int s[MAX]

s[0] s[1] s[2] s[3] s[4] s[5]

3 4 2 6 2 9 …

s = 0x 40ea 0800

変数 int i

変数 int j

変数 int d

(21)

printf("rmdup(s)\n");

rmdup(s);

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

rmdup(s)

s[0] s[1] s[2] s[3] s[4] s[5]

3 4 2 6 2 9 …

s = 0x 40ea 0800

(22)

printf("rmdup(s)\n");

rmdup(s);

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

rmdup(s)

s[0] s[1] s[2] s[3] s[4] s[5]

3 4 2 6 2 9 …

s = 0x 40ea 0800

(23)

printf("rmdup(s)\n");

rmdup(s);

printf("s[]: ");

printset(s);

return 0;

int main( void) 変数 int s[MAX]

rmdup(s)

s[0] s[1] s[2] s[3] s[4] s[5]

3 4 2 6 2 9 …

s = 0x 40ea 0800 仮引数 int a[]

40ea0800

for(i=0; a[i] != EOSET; i++) for(j=i+1; a[j] != EOSET; j++) if (a[j] == a[i])

a[j] = NOTMEMBER;

d = 0;

for(i=0; a[i] != EOSET; i++) if (a[i] == NOTMEMBER) d++;

else { if (d > 0) a[i-d] = a[i];

} a[i-d] = a[i];

戻り値なし( void ) void rmdup( int a[] )

変数 int i

変数 int j

変数 int d

rm dup (40 ea0 800 )

(24)

rmdup(s)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

40ea0800

仮引数 int a[]

for(i=0; a[i] != EOSET; i++) for(j=i+1; a[j] != EOSET; j++) if (a[j] == a[i])

a[j] = NOTMEMBER;

d = 0;

for(i=0; a[i] != EOSET; i++) if (a[i] == NOTMEMBER) d++;

else { if (d > 0) a[i-d] = a[i];

} a[i-d] = a[i];

戻り値なし( void ) void rmdup( int a[] )

変数 int i 変数 int j 変数 int d

rmdup からは、配列名 a によって配列 s を参照している

: 配列 a だと思えばよい。

(25)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

i = 0

1 j =

a[j] == a[i] ?

(26)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

i = 0

2 j =

a[j] == a[i] ?

(27)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

i = 0

3 j =

a[j] == a[i] ?

(28)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

i = 0

… j =

a[j] == a[i] ?

a[j] == EOSET までループ(内側のループ)

(29)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

i = 1

2 j =

a[j] == a[i] ?

i に 1 を追加(外側のループ)

(30)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

i = 1

3 j =

a[j] == a[i] ?

(31)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

… j =

a[j] == a[i] ?

a[j] == EOSET までループ(内側のループ)

i = 1

(32)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

i = 2 i に 1 を追加(外側のループ)

3 j =

a[j] == a[i] ?

(33)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6 2 9 …

i = 2

4 j =

a[j] == a[i] ビンゴ!

(34)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6

NUMBERNOT

9 …

i = 2

4 j =

a[j] == a[i] ビンゴ!

(35)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6

NUMBERNOT

9 …

i = 2

… j =

a[j] == a[i] ?

a[j] == EOSET までループ(内側のループ)

(36)

a[0] a[1] a[2] a[3] a[4] a[5]

3 4 2 6

NUMBERNOT

9 …

i = …

… j =

a[j] == a[i] ?

a[i] == EOSET までループ(外側のループ)

(37)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6

NUMBERNOT

9

NUMBERNOT NUMBERNOT

1 …

i = 0

0

d =

(38)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6

NUMBERNOT

9

NUMBERNOT NUMBERNOT

1 …

i = 1

0

d =

(39)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6

NUMBERNOT

9

NUMBERNOT NUMBERNOT

1 …

i = 2

0

d =

(40)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6

NUMBERNOT

9

NUMBERNOT NUMBERNOT

1 …

i = 3

0

d =

(41)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6

NUMBERNOT

9

NUMBERNOT NUMBERNOT

1 …

i = 4

1

d =

(42)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6

NUMBERNOT

9

NUMBERNOT NUMBERNOT

1 …

i = 5

1 d =

a[ i-d] = a[i];

(43)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6 9 9

NUMBERNOT NUMBERNOT

1 …

i = 5

1 d =

a[ i-d] = a[i];

(44)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6 9 9

NUMBERNOT NUMBERNOT

1 …

i = 6

2

d =

(45)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6 9 9

NUMBERNOT NUMBERNOT

1 …

i = 7

3

d =

(46)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6 9 9

NUMBERNOT NUMBERNOT

1 …

i = 8

3 d =

a[ i-d] = a[i];

(47)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]

3 4 2 6 9 1

NUMBERNOT NUMBERNOT

1 …

i = 8

3 d =

a[ i-d] = a[i];

(48)

a[0] a[1] a[2] a[3] a[4] a[5] a[…] a[.] a[8]

3 4 2 6 9 1 …

EOSET

1 …

15 i =

… d =

a[ i-d] = a[i];

(49)

a[0] a[1] a[2] a[3] a[4] a[5] a[…]

3 4 2 6 9 1 …

` 15 i =

40ea0800

仮引数 int a[]

for(i=0; a[i] != EOSET; i++) for(j=i+1; a[j] != EOSET; j++) if (a[j] == a[i])

a[j] = NOTMEMBER;

d = 0;

for(i=0; a[i] != EOSET; i++) if (a[i] == NOTMEMBER) d++;

else { if (d > 0) a[i-d] = a[i];

} a[i-d] = a[i];

戻り値なし( void ) void rmdup( int a[] )

変数 int i

変数 int j

変数 int d

(50)

printf("rmdup(s)\n");

rmdup(s);

printf("s[]: ");

printset(s);

return 0;

int main( void)

変数 int s[MAX]

s[0] s[1] s[2] s[3] s[4] s[5]

3 4 2 6 2 9 …

s = 0x 40ea 0800

a[0] a[1] a[2] a[3] a[4] a[5] a[…]

3 4 2 6 9 1 …

15 i =

40ea0800

仮引数 int a[]

for(i=0; a[i] != EOSET; i++) for(j=i+1; a[j] != EOSET; j++) if (a[j] == a[i])

a[j] = NOTMEMBER;

d = 0;

for(i=0; a[i] != EOSET; i++) if (a[i] == NOTMEMBER) d++;

else { if (d > 0) a[i-d] = a[i];

} a[i-d] = a[i];

戻り値なし( void ) void rmdup( int a[] )

変数 int i 変数 int j 変数 int d

re tu rn

rmdup(s)

(51)

printf("rmdup(s)\n");

rmdup(s);

printf("s[]: ");

printset(s);

return 0;

int main( void)

変数 int s[MAX]

s[0] s[1] s[2] s[3] s[4] s[5]

3 4 2 6 2 9 …

s = 0x 40ea 0800

s[0] s[1] s[2] s[3] s[4] s[5] s[…]

3 4 2 6 9 1 …

rmdup(s)

s[0] s[1] s[2] s[3] s[4] s[5]

3 4 2 6 2 9 …

rmdup(s) の呼び出し前

rmdup(s) から参照されて、

main 関数内の自動配列変数 s の中身が

変更された。

(52)

printf("rmdup(s)\n");

rmdup(s);

printf("s[]: ");

printset(s);

return 0;

int main( void)

変数 int s[MAX]

s[0] s[1] s[2] s[3] s[4] s[5]

3 4 2 6 2 9 …

s = 0x 40ea 0800

s[0] s[1] s[2] s[3] s[4] s[5] s[…]

3 4 2 6 9 1 …

rmdup(s)

s[]: 3 4 2 6 9 1 5 6 8

参照

関連したドキュメント

不変量 意味論 何らかの構造を保存する関手を与えること..

CIとDIは共通の指標を採用しており、採用系列数は先行指数 11、一致指数 10、遅行指数9 の 30 系列である(2017

前章 / 節からの流れで、計算可能な関数のもつ性質を抽象的に捉えることから始めよう。話を 単純にするために、以下では次のような型のプログラム を考える。 は部分関数 (

・逆解析は,GA(遺伝的アルゴリズム)を用い,パラメータは,個体数 20,世 代数 100,交叉確率 0.75,突然変異率は

例えば、総トン数 499 トン・積載トン数 1600 トン主機関 1471kW(2000PS)の内航貨 物船では、燃料油の加熱に使用される電力は

マニピュレータで、プール 内のがれきの撤去や燃料取 り出しをサポートする テンシルトラスには,2本 のマニピュレータが設置さ

マニピュレータで、プール 内のがれきの撤去や燃料取 り出しをサポートする テンシルトラスには,2本 のマニピュレータが設置さ

章番号 ページ番号 変更後 変更前 変更理由.. 1 補足説明資