|
GiPyeong Lee |
|
selection_sort.c |
|
// studentID : A889056 // selection_sort.c // Algorithm_Hongik // // Created by GiPyeong Lee on 2015. 3. 3.. // Copyright (c) 2015 年 com.devsfolder.Hongik. All rights reserved. // #include <stdio.h> #include <time.h> #include <stdlib.h> int tempArray[ 1000001 ]={ 0 ,}; // 容器 void selection_sort( int argc, const char * argv[]){ if ( argc <= 2 ) /* argc 應為 2,以便正確執行檔案並指定測試案例數量 */ { printf ( "Please Input Correctly Arguments (eg. selection_sort hw1_input.txt 1000\n" ); } else { // 正確的參數 int i,j; int min,temp; FILE *file = fopen ( argv[ 1 ], "r" ); // 開啟檔案指標 char number[ 11 ]; // 用於讀取檔案中逐行物件的數字容器 int lineCounter= 0 ; // 檢查行數 int maxCount = atoi (argv[ 2 ]); while ( fgets (number, sizeof (number), file)){ if (lineCounter==maxCount){ break ; } tempArray[lineCounter] = atoi (number); // 設定整數未排序陣列 lineCounter++; } fclose (file); // 關閉檔案指標 for (i= 0 ; i<maxCount; i++) { min = i; // 設定目前索引 for (j=i+ 1 ; j<maxCount; j++) { if (tempArray[min]>tempArray[j]){ min = j; } } temp = tempArray[min]; tempArray[min] = tempArray[i]; tempArray[i]=temp; } for (i= 0 ;i<maxCount;i++){ printf ( "%d\n" ,tempArray[i]); } } } int main( int argc, const char * argv[]) { // 在此插入程式碼... clock_t start_time, end_time; // 宣告時間變數 start_time = clock (); // 開始時間 selection_sort (argc,argv); end_time = clock (); // 結束時間 printf ( "Running time = %.1f ms\n" , (( double )(end_time-start_time)) / CLOCKS_PER_SEC * 1000 ); return 0 ; } |
|
Insertion_sort.c |
|
// studentID : A889056 // insertion_sort.c // Algorithm_Hongik // // Created by GiPyeong Lee on 2015. 3. 4.. // Copyright (c) 2015 年 com.devsfolder.Hongik. All rights reserved. // #include <stdio.h> #include <time.h> #include <stdlib.h>
int tempArray[ 1000001 ]={ 0 ,}; // 容器 void insertion_sort( int argc, const char * argv[]){ if ( argc <= 2 ) /* argc 應為 2,以便正確執行檔案並指定測試案例數量 */ { printf( "Please Input Correctly Arguments (eg. selection_sort hw1_input.txt 1000\n" ); } else { // 正確的參數 > 執行任務 :) int i,j; int temp; FILE *file = fopen( argv[ 1 ], "r" ); // 開啟檔案指標 char number[ 11 ]; // 用於讀取檔案中逐行物件的數字容器 int lineCounter= 0 ; // 檢查行數 int maxCount = atoi(argv[ 2 ]); while (fgets(number, sizeof (number), file)){ if (lineCounter==maxCount){ break ; } tempArray[lineCounter] = atoi(number); // 設定整數未排序陣列 lineCounter++; } fclose(file); // 關閉檔案指標 for (i= 1 ; i<maxCount; i++) { temp = tempArray[i]; j=i- 1 ; while ((temp<tempArray[j])&&(j>= 0 )){ tempArray[j+ 1 ]=tempArray[j]; j=j- 1 ; } tempArray[j+ 1 ]=temp; } for (i= 0 ;i<maxCount;i++){ printf( "%d\n" ,tempArray[i]); } } } int main( int argc, const char * argv[]) { // 在此插入程式碼... clock_t start_time, end_time; // 宣告時間變數 start_time = clock(); // 開始時間 insertion_sort(argc,argv); end_time = clock(); // 結束時間 printf( "Running time = %.1f ms\n" , (( double )(end_time-start_time)) / CLOCKS_PER_SEC * 1000 ); return 0 ; } |
|
圖表 |
|
對數圖 |
|
結論 |
|
在測試完「選擇排序」與「插入排序」兩種排序演算法後,當未排序數字的數量超過 10,000 個時,插入排序比選擇排序快。時間幾乎縮短了一半。 但如果我們使用插入排序將遞減數字改為遞增排序,那麼執行時間可能與選擇排序相同。 |
以下是教授針對此作業提出的指正事項:
- 在 main 以外的函式中配置 1,000,000 個(4MB)的區域變數是非常不好的方式/習慣。
- 區域變數會進入作業系統的堆疊(stack),而堆疊有大小限制。
- 若該函式被多次呼叫,程式將會崩潰。
- 像這樣的大型變數應設為全域變數、放在 main 中,或者使用 malloc/free 進行動態配置。
修正程式碼後,我又進一步了解了相關知識。
程式碼修正
// studentID : A889056
// selection_sort.c
// Algorithm_Hongik
//
// Created by GiPyeong Lee on 2015. 3. 3..
// Copyright (c) 2015年 com.devsfolder.Hongik. All rights reserved.
//
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int tempArray[1000001]={0,}; // 容器
void selection_sort(int argc, const char * argv[]){
if ( argc <= 2 ) /* argc 應為 2,以便正確執行檔案並指定測試案例數量 */
{
printf("Please Input Correctly Arguments (eg. selection_sort hw1_input.txt 1000\n");
return;
}
// 正確的參數
int i,j;
int min,temp;
FILE *file = fopen( argv[1], "r" ); // 開啟檔案指標
char number[11]; // 用於讀取檔案中逐行物件的數字容器
int lineCounter=0; // 檢查行數
int maxCount = atoi(argv[2]);
while(fgets(number, sizeof(number), file)){
if(lineCounter==maxCount){
break;
}
tempArray[lineCounter] = atoi(number); // 設定整數未排序陣列
lineCounter++;
}
fclose(file); // 關閉檔案指標
for (i=0; i<maxCount; i++) {
min = i; // 設定目前索引
for (j=i+1; j<maxCount; j++) {
if(tempArray[min]>tempArray[j]){
min = j;
}
}
temp = tempArray[min];
tempArray[min] = tempArray[i];
tempArray[i]=temp;
}
for(i=0;i<maxCount;i++){
printf("%d\n",tempArray[i]);
}
}
int main(int argc, const char * argv[]) {
// 在此插入程式碼...
clock_t start_time, end_time; // 宣告時間變數
start_time = clock(); // 開始時間
selection_sort(argc,argv);
end_time = clock(); // 結束時間
printf("Running time = %.1f ms\n", ((double)(end_time-start_time)) / CLOCKS_PER_SEC * 1000);
return 0;
}
// studentID : A889056
// insertion_sort.c
// Algorithm_Hongik
//
// Created by GiPyeong Lee on 2015. 3. 4..
// Copyright (c) 2015年 com.devsfolder.Hongik. All rights reserved.
//
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int tempArray[1000001]={0,}; // 容器
void insertion_sort(int argc, const char * argv[]){
if ( argc <= 2 ) /* argc 應為 2,以便正確執行檔案並指定測試案例數量 */
{
printf("Please Input Correctly Arguments (eg. selection_sort hw1_input.txt 1000\n");
return;
}
// 正確的參數 > 執行任務 :)
int i,j;
int temp;
FILE *file = fopen( argv[1], "r" ); // 開啟檔案指標
char number[11]; // 用於讀取檔案中逐行物件的數字容器
int lineCounter=0; // 檢查行數
int maxCount = atoi(argv[2]);
while(fgets(number, sizeof(number), file)){
if(lineCounter==maxCount){
break;
}
tempArray[lineCounter] = atoi(number); // 設定整數未排序陣列
lineCounter++;
}
fclose(file); // 關閉檔案指標
for (i=1; i<maxCount; i++) {
temp = tempArray[i];
j=i-1;
while((temp<tempArray[j])&&(j>=0)){
tempArray[j+1]=tempArray[j];
j=j-1;
}
tempArray[j+1]=temp;
}
for(i=0;i<maxCount;i++){
printf("%d\n",tempArray[i]);
}
}
int main(int argc, const char * argv[]) {
// 在此插入程式碼...
clock_t start_time, end_time; // 宣告時間變數
start_time = clock(); // 開始時間
insertion_sort(argc,argv);
end_time = clock(); // 結束時間
printf("Running time = %.1f ms\n", ((double)(end_time-start_time)) / CLOCKS_PER_SEC * 1000);
return 0;
}
記憶體區域
當我們使用特定語言編寫程式碼,經過編譯並執行時,變數與函式會儲存在如下的記憶體結構中。
資料區(Data Area)
資料區是分配全域變數與 static 變數的區域。在此區域分配的變數通常會在程式啟動時同步分配,並直到程式結束時才會從記憶體中清除。換句話說,資料區分配的變數具有會持續存在直到程式結束的特徵。這與全域變數與 static 變數的特性一致。
堆疊區(Stack Area)
堆疊區是儲存函式呼叫時所產生的區域變數與參數的區域。此區域分配的變數具有會在函式呼叫結束後消失的特性。這與其他記憶體區域有顯著的區別。後分配的變數記憶體會先被釋放,這與堆疊(Stack)的特性一致。
堆積區(Heap Area)
堆積區是由程式設計師管理的記憶體區域。也就是說,這是根據程式設計師的需求分配及銷毀記憶體空間的區域,是透過動態配置產生的記憶體區域。
※ 靜態分配變數的記憶體會根據變數的特性,在資料區或堆疊區中產生。靜態分配在編譯階段(Compile-time)即全部完成。然而,編譯階段只會產生記憶體大小,並不會儲存變數的值。這就是為什麼陣列大小必須指定為常數的原因。變數值的儲存是在執行階段(Run-time)完成的,而為了在執行階段產生記憶體所使用的技術即為動態配置。
這時產生了一個疑問...
如果 Heap 和 Stack 都滿了會發生什麼事呢?