本日の目標
- ソートのアルゴリズムを理解して、利用することができる。
- 構造体を使って表されるデータをソートすることができる。
予習・復習
以下のスライドを利用して、予習と復習をしよう。復習では、自分の理解度を確認するために、実際にプログラムを作成し、意図する結果が得られるか確認しよう。本日の講義・演習予定
- 線形探索
- 二分探索
- 計算量
- 演習問題
- 提出課題
#define <stdio.h> #define N 10 void print_array(int a[], int size); void simple_sort(int a[], int size); int main(void) { int data[N] = {21,12,8,65,22,40,34,17,7,51}; printf("before: "); print_array(data,N); simple_sort(data,N); printf("after : "); print_array(data,N); return 0; } /* 単純ソート */ void simple_sort(int a[], int n) { int i,j,tmp; for(i=0; i <size-1; i++){ // i番目の要素と for(j=i+1; j<size; j++){ // それ以外の未ソートの要素を if(a[i] > a[j]){ // 比較し、左側の要素が大きければ tmp = a[i]; // 交換 a[i] = a[j]; a[j] = tmp } } } }
#include <stdio.h> #define swap(a,b){ int tmp; tmp=a; a=b; b=tmp; } int main(void) { int x=3,y=7; swap(x,y); /* swap(x,y);以下のように展開される { int tmp; tmp = x; x = y; y = tmp; }; */ printf("%d %d\n",x,y); return 0; }
#include <stdio.h> #define swap(a,b) { int tmp; tmp=a; a=b; b=tmp; } int main(void) { int x=3, y=7; if(x>y) swap(x,y); /* { int tmp; tmp=a; a=b; b=tmp; }; <--セミコロンでifが終了してしまう */ else printf("Without the need to swap.\n"); printf("%d %d\n",x,y); return 0; }このような場合の対応策として、do while文が利用できます。
#define swap(type, a,b) do{ type tmp; tmp=a; a=b; b=tmp; }while(0)
void ins_sort(int a[], int n) { int i,j,tmp; for(i=1; i<n; i++){ tmp = a[i]; // 退避 for(j=i-1; j>=0 && a[j]>tmp; j--){ //前方のデータがtmpより大きい場合 a[j+1] = a[j]; // 後方へ移動 } a[j+1] = tmp; // 挿入 } }
void shell_sort(int a[], int n) { int i,j,k,h,x; for(h=n/2; h>0; h/=2){ // 間隔を1になるまで半分に狭める for(k=0; k<h; k++){ // グループ数分繰り返す for(i=k+h; i<n; i+=h){ //以下挿入ソート x = a[i]; for(j=i-h; j>=k && a[j]>x; j-=h) a[j+h] = a[j]; a[j+h] = x; //挿入 } } } }
#include <stdio.h> void merge(int a[], int na, int b[], int nb, int c[]) { int i=0,j=0,k=0; while(i<na && j<nb) c[k++] = a[i]<b[j] ? a[i++] : b[j++]; //小さい方の値を格納 while(i<na) c[k++] = a[i++]; //残った要素を格納 while(j<nb) c[k++] = b[j++]; } int main(void) { int a[3] = {1,5,6}; int b[2] = {3,7}; int c[5]; int i; merge(a,3,b,2,c); for(i=0; i<5; i++) printf("%d,",c[i]); printf("\n"); return 0; }
#include <stdio.h> #include <stdlib.h> #define N 10 //プロトタイプ宣言 void merging(int left,int mid,int right); void merge_sort(int left, int right); void print_array(void); int a[N] = {21,12,8,65,22,40,34,17,7,5}; int work[N]; //作業用(マージ結果格納用) void merging(int left,int mid,int right) { int i,j,k; i=left; //配列の左半分の先頭 j=mid+1; //配列の右半分の先頭 k=left; //マージ結果格納用配列のインデックス while(i<=mid && j<=right) work[k++] = a[i]<=a[j] ? a[i++] : a[j++]; //小さい方の値を格納 while(i<=mid) work[k++] = a[i++]; //残った要素を格納 while(j<=right) work[k++] = a[j++]; for(i=left; i<=right; i++) a[i] = work[i]; } void merge_sort(int left, int right){ int mid; if(left<right){ mid = (left+right)/2; //中央の位置を取得 merge_sort(left,mid); //左半分ソート(要素数が1になるまで再帰的に) merge_sort(mid+1,right); //右半分ソート(要素数が1になるまで再帰的に) merging(left,mid,right); //マージ } } int main(void) { int i; printf("Before :"); for(i=0; i<N; i++) printf(" %2d,",a[i]); printf("\n"); merge_sort(0,N-1); printf("After :"); for(i=0; i<N; i++) printf(" %2d,",a[i]); printf("\n"); return 0; }
void quick_sort(int a[], int left, int right) { int pl,pr,pivot; if(left>=right) return; //交差していたら要素が1つだけと判断し終了 pivot = a[(left + right)/2]; //配列の中央の要素を枢軸とする pl=left; //小さい値グループ(左側)のインデックス pr=right; //大きい値グループ(右側)のインデックス while(pl<=pr){ while(a[pl] < pivot) pl++; //右端Gから枢軸以上の値が現れるまで走査 while(a[pr] > pivot) pr--; //左端Gから枢軸以下の値が現れるまで走査 if(pl<=pr){ //走査が交差していなければ swap(a[pl],a[pr]); //左右の要素を入れ替える pl++; pr--; } } quick_sort(a,left,pr); //左側グループを再帰的にソート quick_sort(a,pl,right); //右側グループを再帰的にソート }
struct student{ int id; char name[32]; int score; }
#include <stdio.h> #define swap(a,b) { int tmp=a; a=b; b=tmp; } #define N 10 void select_sort_dec(int a[], int n); void bubble_sort(int a[], int n); void ins_sort_dec(int a[], int n); void print_array(int a[],int n); int main(void) { int a[] = {6,3,17,8,2,7,12,11,5,15}; printf("Before: "); print_array(a,N); //select_sort_dec(a,N); //bubble_sort(a,N); ins_sort_dec(a,N); printf("After : "); print_array(a,N); return 0; } /* 単純選択ソート(降順) */ void select_sort_dec(int a[], int n) { int i,j; for(i=0; i<n-1; i++) for(j=i+1; j<n; j++) if(a[i]<a[j]) swap(a[i],a[j]); } /* バブルソート */ void bubble_sort(int a[], int n) { int i,j; for(i=0;i<n-1; i++){ for(j=n-1; j>i; j--) if(a[j-1]>a[j]) swap(a[j-1],a[j]); print_array(a,n); } } /* 挿入ソート(降順) */ void ins_sort_dec(int a[], int n) { int tmp,i,j; for(i=1; i<n; i++){ tmp = a[i]; for(j=i-1; j>=0 && a[j]<tmp; j--) a[j+1] = a[j]; a[j+1] = tmp; } } void print_array(int a[],int n) { int i; for(i=0; i<n; i++) printf("%d ",a[i]); printf("\n"); }
#include <stdio.h> #include <limits.h> #define N 10 void print_array(int a[], int n); int a[N] = {21,12,8,65,22,40,34,17,7,5}; int al[N],ar[N]; void merging(int left, int mid, int right) { int i,j=0,k=0; for(i=left; i<=mid; i++) al[j++] = a[i]; al[j] = INT_MAX; //番兵 print_array(al,j); for(i=mid+1; i<=right; i++) ar[k++] = a[i]; ar[k] = INT_MAX; //番兵 print_array(ar,k); for(i=left,j=0,k=0; i<=right; i++) a[i] = al[j] <ar[k] ? al[j++] : ar[k++]; } void merge_sort(int left, int right) { int mid; if(left < right){ mid = (left + right)/2; merge_sort(left,mid); merge_sort(mid+1,right); merging(left,mid,right); } } void print_array(int a[], int n) { int i; for(i=0; i<n; i++) printf("%d ",a[i]); printf("\n"); } int main(void) { printf("Before: "); print_array(a,N); merge_sort(0,N-1); printf("After : "); print_array(a,N); return 0; }
#include <stdio.h> #include <stdlib.h> #define N 10 //プロトタイプ宣言 void merging(int a[], int left,int mid,int right); void _merge_sort(int a[], int left, int right); int merge_sort(int a[], int n); void print_array(int a[], int n); int *work; //作業用領域 void merging(int a[], int left,int mid,int right) { int i,wi,j=0; int k=left; for(i=left,wi=0; i<=mid; i++,wi++) work[wi] = a[i]; //左半分のみコピー //左半分workと右半分aを比較して、小さい方をaの先頭から格納する while(i<=right && j<wi) a[k++] = work[j]<=a[i] ? work[j++] : a[i++]; //workに残っている要素があればaに移す while(j<wi) a[k++] = work[j++]; } void _merge_sort(int a[], int left, int right) { int mid; if(left<right){ mid = (left+right)/2; //中央の位置を取得 _merge_sort(a,left,mid); //左半分ソート _merge_sort(a,mid+1,right); //右半分ソート printf("--> %d %d %d\n",left,mid,right); merging(a,left,mid,right); //マージ } } int merge_sort(int a[], int n) { //作業用領域確保 if((work = calloc(n,sizeof(int))) == NULL) return -1; _merge_sort(a,0,n-1); //マージソート呼び出し free(work); //作業用領域解放 return 0; } void print_array(int a[], int n) { int i; printf("["); for(i=0; i<n; i++) printf(" %2d,",a[i]); printf("]\n"); } int main(void) { int a[N] = {21,12,8,65,22,40,34,17,7,5}; int i; printf("Before "); print_array(a,N); merge_sort(a,N); printf("After "); print_array(a,N); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 10 //データ数 struct student_s { int id; char name[32]; int score; }; typedef struct student_s Student; void swap_student(Student *p, Student *q); void simple_sort(Student *); void simple_sort(Student *sp) { int i,j,max; for(i=0; i<N-1; i++){ max = i; for(j=i+1; j<N; j++){ if((sp+j)->score > (sp+max)->score) max = j; } swap_student(sp+i, sp+max); } } void swap_student(Student *p, Student *q) { int tmp; char tmpc[32]; tmp = p->id; p->id = q->id; q->id = tmp; strcpy(tmpc,p->name); strcpy(p->name,q->name); strcpy(q->name,tmpc); tmp = p->score; p->score = q->score; q->score = tmp; } int main(void) { FILE *fp; char filename[32] = "achievement.data"; Student *sp; int i,j; sp = (Student *)malloc(sizeof(Student)*N); if((fp=fopen(filename,"r"))==NULL){ fprintf(stderr,"Can't open %s.\n",filename); return EXIT_FAILURE; } printf("------ READ DATA ------\n"); for(i=0; i<N; i++){ fscanf(fp,"%d,%[^,],%d",&(sp+i)->id,(sp+i)->name,&(sp+i)->score); printf("%d %s %d\n",(sp+i)->id,(sp+i)->name,(sp+i)->score); } fclose(fp); simple_sort(sp); printf("------ RESULT ------\n"); for(i=0; i<N; i++){ printf("%d %s %d\n",(sp+i)->id,(sp+i)->name,(sp+i)->score); } free(sp); return 0; }
今週の確認テスト テスト(PDF)
#include <stdio.h> /* 挿入ソート(昇順) a[]: 配列データ, n:データ数 */ void ins_sort(int a[], int n) { // ここを埋める } /* ソート済みデータへのデータの追加 a[]: 配列データ, n:データ数, x: 追加データ */ void ins_data(int a[], int n, int x) { //ここを埋める } /* 配列データの表示 */ void print_array(int a[], int n) { //ここを埋める } int main(void) { int data[10] = {19,7,34,78,40,65,21,83,51}; int a; ins_sort(data,9); printf("ソート済み:\n"); print_array(data,9); printf("\n追加データ> "); scanf_s("%d",&a); ins_data(data,10,a); print_array(data,10); //結果表示 return 0; }
ソート済み: 7 19 21 34 40 51 65 78 83 追加データ> 68 7 19 21 34 40 51 65 68 78 83