(資料3)L

Download Report

Transcript (資料3)L


生活を豊かにする便利なもの
◦
◦
◦
◦
◦

インターネット端末
ワード・プロセッサ
電子書籍リーダ
携帯電話
etc
どんなシステム???

融通のきかない人
◦ あらかじめ決められた手続きしかできない
◦ 決まった言葉(言語・文法)しか理解できない

プログラム
◦ コンピュータに行わせる一連の手続き
◦ 命令の集合として記述
Ex.) C = A + B

Memory
◦ 命令やデータを格納する領域

CPU(Central Processing Unit)
◦ メモリから命令やデータを取得
◦ 演算を行う装置
詳しくは『計算システム論第2』で
CPU
C
C=A+B A B
Memory

プログラム
◦ コンピュータに行わせる手続き
 命令の集合
◦ 最終的には機械語(アセンブリ)
 「01001110 …」

人間が直接書くのはほぼ不可能
◦ 昔は書いてた
 『マイコンプログラミング演習』でもやる
◦ ちょっと複雑になると無理

高級言語
Ex.) Fortran, C, Java, Ruby, …
◦ これなら何とかなる(for 人間)
◦ 理解不能(for コンピュータ)

コンパイラ
◦ 翻訳を行うプログラム
◦ 高級言語で記述されたものを機械語へと変換
機械語
高級言語
コンパイル

Visual C++ の場合
◦
◦
◦
◦
◦
◦
◦
◦
◦
◦

Windows を起動
ログインして Visual Studio を起動
メニューから「ファイル」→「新規作成」→「プロジェクト」を選択
「Win32」→「Win32コンソールアプリケーション」を選択し,「プロジェクト名」と
「場所」を入力.「ソリューションのディレクトリを作成」のチェックはOFFにして
「OK」をクリック
Win32アプリケーションウィザードにて「次へ」をクリック.「コンソールアプリ
ケーション」を選択.「空のプロジェクト」にチェックを入れ,「完了」をクリック
メニューから「プロジェクト」→「新しい項目の追加」を選択
「C++ファイル(.cpp)」を選択し,「ファイル名」と「場所」を入力して「追加」をク
リック
プログラムを記述
メニューから「ビルド」→「ソリューションのビルド」(コンパイル)
メニューから「デバッグ」→「デバッグなしで開始」

gcc の場合
◦ Ubuntu を起動
◦ (emacsなどの)テキストエディタを起動し,プログラムを記述
◦ コマンドライン端末を起動し,コマンド「gcc filename」
(filename はプログラムのファイル名)を実行.(正しくコンパイル
ができていれば)「a.out」という名前の実行ファイルができる
◦ 上記のファイルを実行(コマンド「./a.out」を実行)



プログラムの基本構造
データと演算
制御の流れ

問題:
◦ 進振り対象の学生の成績データ(平均点のデータ.3,000人分)が
手元にある.中央値を求めなさい.
Ex.) 75点,95点,63点,70点,82点,・・・

どうやって?
◦ 人間が集計
数日仕事
データを昇順に並び替え(ソート)
1,500人目
1,500人目を探す
Ex.) 60点,60点,62点,63点,65点,・・・,77点,・・・
◦ コンピュータに集計させる
数分仕事

バブル・ソート
◦ 左端から右端に向かって以下の操作を行う
 隣り合うデータの大小を比較
 昇順になっていなかったら入れ替え
◦ 右端に到達したら左端に戻ってやり直し
◦ 計算量:最悪 O (n^2)
1回目
2回目
63点
75点
63点
75点
70点
95点
swap
70点
75点
63点
95点
swap
70点
95点
82点
swap
82点
95点
ヘッダ
#include <stdio.h>
main ( ) {
int i, j, tmp;
int data [3000];
文
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1];
data [ j + 1 ] = tmp;
}
}
}
}
関数
printf ( “median = %d\n”, data [1500] );
ファイル median.c の内容

処理のまとまり
◦ 複数の文からなる

サブルーチンを実現(後述)

普通は繰り返し行われる処理を関数化
◦ 同じことを何度も書くのは面倒
◦ バグのもと

main 関数
◦ プログラムの実行開始地点を表す
◦ 普通は最初に1回呼ばれるだけ
#include <stdio.h>
main ( ) {
int i, j, tmp;
int data [3000];
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1];
data [ j + 1 ] = tmp;
}
}
}
}
printf ( “median = %d\n”, data [1500] );

処理の最小単位
◦ 「A を B に代入する」
◦ 「文字を出力する」


「 ; 」 の次の文字から 「 ; 」 まで
1文/行がマナー(例外アリ)
#include <stdio.h>
main ( ) {
int i, j, tmp;
int data [3000];
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1];
data [ j + 1 ] = tmp;
}
}
}
}
printf ( “median = %d\n”, data [1500] );

ヘッダ・ファイルの展開(include)

ヘッダ・ファイル
◦ 複数のファイルで使用される関数などを宣言
◦ あらかじめ用意されていることもある #include <stdio.h>
main ( ) {
int i, j, tmp;
int data [3000];
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1];
data [ j + 1 ] = tmp;
}
}
}
}
printf ( “median = %d\n”, data [1500] );
文字列を出力する関数
(printf)の宣言があるヘッダ・
ヘッダ
ファイル(stdio.h)を include
プログラムの開始地点
#include <stdio.h>
main ( ) {
バブル・ソートint i, j, tmp;
int data [3000];
処理の方向
文
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
関数
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1];
data [ j + 1 ] = tmp;
}
}
中央値を出力
プログラムの終了
}
}
printf ( “median = %d\n”, data [1500] );
ファイル median.c の内容

プログラムの大部分はデータに対する演算
◦ 「隣り合う2つの点数を比較する」
◦ 「2つの点数を交換する」 など
データ 演算

75
データ
◦ 定数:変更不可
(e.g. “1500”, “3000”)
◦ 変数:値の入れ物.中身を変更可能
(e.g. “i”, “j”, “tmp”)

63
tmp
データ型
◦ データを扱う形式
◦ コンパイラが機械語を生成する際のヒント
 “A + B”
95
整数の加算 or 浮動小数点の加算?

基本型
◦
◦
◦
◦

char:1B の数値.文字の型としても使用
int:整数(通常 4B)
float:単精度浮動小数点(通常 4B)
double:倍精度浮動小数点(通常 8B)
修飾子
◦ 長さ(short, long)
◦ 符号(singed, unsigned)

使い方(変数に限らない)
◦ 最初に型を宣言
◦ どこかで定義(宣言を兼ねることも)
◦ 後は普通に使用

宣言/定義の位置
◦ グローバル
宣言(定義は
別のファイル)
関数の冒頭で
宣言/定義
#include <stdio.h>
main ( ) {
int i, j, tmp;
int data [3000];
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1];
data [ j + 1 ] = tmp;
}
}
}
 関数の外で宣言/定義
 そのファイル中のどこでも参照可能
◦ ローカル
 関数の冒頭で宣言/定義
 その関数内でのみ参照可能
使用
}
printf ( “median = %d\n”, data [1500] );

配列
◦ ベクタ,行列
◦ インデクス付けされたデータの集合
Ex.) 3,000人分の平均点データ
 int data0, data1, …, data2999;
 “data [ i ]” で i 番目の要素にアクセス

ポインタ
◦ データのアドレスを格納する変数
int data [3000];

基本的には同じ型のデータ同士

種類
◦ 算術演算(+, -, *, /, %)
◦ 論理演算(&, |, ^, <<, >>, ~)
◦ 関係演算(<, >, >=, <=, ==)
 結果は真(1) or 偽(0)
◦ 代入演算(=)
 “A = B” は「A に B を代入する」
#include <stdio.h>
main ( ) {
int i, j, tmp;
int data [3000];
j 番目のデータが
j+1 番目のデータ
よりも大きいか比較
j 番目のデータ
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
を tmp に退避
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
}
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1]; データ交換
data [ j + 1 ] = tmp;
}
tmp のデータを
j+1
}
番目の位置に代入
}
j+1 番目のデータを
j 番目の位置に代入
printf ( “median = %d\n”, data [1500] );
ファイル median.c の内容
ソース・コード

基本
◦ 左から右へ
◦ 上から下へ

流れを変えたいこともある
◦ 条件付き実行
 「左のデータの値が右のデータの値よりも大きい場合は交換する」
 「3000回繰り返す(カウンタが3000を超えたら繰り返すのをやめる)」
◦ 関数呼び出し
 “ printf () ”

分岐
◦ if 文
◦ switch 文

ループ
◦ for 文
◦ while 文

サブルーチン

条件によって実行する部分を変更
◦ if 文:
条件の真偽により変更
if ( A ) {
A が真の場合
B;
} else {
A が偽の場合
C;
}
◦ switch 文:
条件の値により変更
switch ( x ) {
case 0:
A;
x が0の場合
break;
case 1:
x が1の場合
B;
break;
}
#include <stdio.h>
main ( ) {
int i, j, tmp;
int data [3000];
j 番目のデータが
j+1 番目のデータ
よりも大きいか比較
結果が真の場合
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
のみ交換を行う
}
}
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1];
data [ j + 1 ] = tmp;
}
}
printf ( “median = %d\n”, data [1500] );
ファイル median.c の内容

条件が成立している限り繰り返す

書き方は2通り
条件式
while ( B ) {
B B
◦ for 文 / while 文
D;
}
◦ どちらでも同じことが実現可能
D D
条件式
◦ 慣例として,
制御変数
制御変数
 for 文:制御変数が単調に変化する時
の初期化
の更新
(配列アクセスなど)
 while 文:それ以外
A
for ( A ; B ; C ) {
D;
}
B B
D D
C C
#include <stdio.h>
i
i が 2999 に達
main ( ) {
int i, j, tmp;するまで繰り返す
を初期化
int data [3000];
i をインクリメント
for ( i = 0 ; i < 3000 – 1 ; i = i + 1) {
for ( j = 0 ; j < 3000 – i + 1 ; j = j + 1) {
if ( data [ j ] > data [ j + 1 ] ) {
tmp = data [ j ];
data [ j ] = data [ j + 1];
data [ j + 1 ] = tmp;
}
}
}
}
printf ( “median = %d\n”, data [1500] );
ファイル median.c の内容

サブルーチン
◦ 別の処理を呼び出す
◦ 終わったら元の位置に戻る
◦ 関数呼び出し/復帰によって実現

関数
◦ 引数:呼び出し時に関数に渡す
データ
◦ 返り値:復帰時に元のルーチン
に返すデータ
返り値の型
第1引数
void printf ( char* s, … ) {
}
printf ( “median = %d\n”, data [1500] );

プログラムの基本構造

データと演算
◦ データには型が存在

制御の流れ
◦ 基本は左から右へ.上から下へ
◦ 流れを変えるもの
 分岐,ループ,関数呼び出し

カーニハン&リッチー:
「プログラミング言語C 第2版」,共立出版

正直に言って,あまりよくない
◦ 「どうしたらいいかわからない」
◦ 「教え方が不親切.できる人にはこれでいいんだろうけど...」

でも,こちらの立場としては,
◦ 理解度のばらつきが大きすぎて,実験の最低ラインを決めるのが
非常に難しい(あまりに易しくしすぎると,できる人には物足りない
演習になる)
◦ 誰が何をわかってないのかこちらはわからないので,わからないこ
とがあるなら質問してほしい(実験の間は室にいるのだから)
できない人をサポートしつつ,できる
人も楽しめる演習にするにはどうす
ればよいか?

サンプル・プログラムを配ります
◦ データ・ファイルの読み込み,結果の出力部分など,アルゴリズム
とは直接関係ない部分を実装する手間を削減
◦ アルゴリズムの考案・実装に注力できるようになる

サンプル・プログラム
◦ tsp.c (資料4)
※ あくまでサンプルなので,ゼロから自分で書きたい人は自由に書
いてください
直前にいた都市
の座標(X, Y)
訪問中の都市
の座標(X, Y)
この都市に訪問するまで
のトータルの移動距離
1行が都市間の
移動1回を表す