選擇排序---while( scanf("%d",&n)!= EOF)與getchar()簡介及其存在的問題,
阿新 • • 發佈:2019-02-02
基本思想:
n個記錄的檔案的直接選擇排序可經過n-1趟直接選擇排序得到有序結果: ①初始狀態:無序區為R[1..n],有序區為空。 ②第1趟排序 在無序區R[1..n]中選出關鍵字最小的記錄R[k],將它與無序區的第1個記錄R[1]交換,使R[1..1]和R[2..n]分別變為記錄個數增加1個的新有序區和記錄個數減少1個的新無序區。 …… ③第i趟排序 第i趟排序開始時,當前有序區和無序區分別為R[1..i-1]和R(i..n)。該趟排序從當前無序區中選出關鍵字最小的記錄 R[k],將它與無序區的第1個記錄R交換,使R[1..i]和R分別變為記錄個數增加1個的新有序區和記錄個數減少1個的新無序區。#include<stdio.h> #include<stdlib.h> int *select_sort(int a[],int n) { int i; //迴圈因子 int j; //迴圈因子 int k; //儲存每次迴圈中最大值的下標 int temp; for(i=0;i<n;++i) { k = i; //假設第一個數最大,所以把每次迴圈的第一個數的下標賦給k for(j=i+1;j<n;++j)//和後面的數值依次比較,將最大值的下標賦給k { if(a[j] > a[k]) { k = j; } } if(k != i) //每次迴圈的最大值的下標不是本身(若是本身就不用交換了) { temp = a[i]; a[i] = a[k]; a[k] = temp; } } return a; } void my_printf(int a[],int n) { int i; for(i=0;i<n;i++) { printf("%d\n",a[i]); } } int main() { system("mode con cols=100 lines=100"); system("color 0A"); int a[] = {8,5,7,3,9,12,6}; int n = sizeof(a)/sizeof(a[0]); select_sort(a,n); my_printf(a,n); system("pause"); return 0; }
要是動態輸入要排序的數,該怎麼辦?
#include<stdio.h> #include<stdlib.h> void my_swap(int a[],int i,int j) { int tmp; tmp = a[i]; a[i] = a[j]; a[j] = tmp; } int *quick_sort(int a[],int n) { int i; //迴圈因子 int j; //迴圈因子 int k; //儲存每次迴圈中最大值的下標 for(i=0;i<n;++i) { k = i; //假設第一個數最大,所以把每次迴圈的第一個數的下標賦給k for(j=i+1;j<n;++j)//和後面的數值依次比較,將最大值的下標賦給k { if(a[j] > a[k]) { k = j; } } if(k != i) //每次迴圈的最大值的下標不是本身(若是本身就不用交換了) { my_swap(a,k,i); } } return a; } void my_printf(int a[],int n) { int i; for(i=0;i<n;i++) { printf("%d\n",a[i]); } } int main() { system("mode con cols=100 lines=100"); system("color 0A"); int n; int i; int *array; printf("how many nums do you want to sort:"); while( scanf("%d",&n)!= EOF)//當輸入為ctrl+z時結束迴圈 { array = (int *)malloc(sizeof(int)*n);//動態開闢空間 printf("please input %d num:\n",n); for(i=0;i<n;i++) { scanf("%d",&array[i]);//初始化陣列 } } quick_sort(array,n); printf("the sorted num:\n"); my_printf(array,n); system("pause"); return 0; }
while( scanf("%d",&n)!= EOF)介紹及其存在的問題:
說實話,以前沒見過這種寫法,沒注意scanf還有返回值,EOF也沒怎麼見過。百度了一番,知道EOF是-1(即#define EOF (-1));
scanf返回的是成功掃描進的數的個數。如scanf("%d %d",&a, &b),若a、b都輸入成功返回2,成功一個返回1,都不成功返回0,錯誤返回-1。
這段程式碼的意思是,輸入Ctrl+z終止迴圈(這是在Windows下,在Unix環境下是Ctrl+d)。如果你輸入字元a,而迴圈體裡又沒有getchar之類讀字元的函式,就會死迴圈,因為a會一直留在輸入緩衝區中。
要想在輸入錯誤的情況下終止把 !=EOF 去掉就行了,即成功輸入的個數為0的情況下推出迴圈。
在百度過程中見到有while(~scanf("%d",&n)!=EOF)這種寫法,找不到具體的解釋。後來找到“~”的解釋是是取反,即0變1,1變0。試了一下這種方式在輸入錯誤的情況下就退出迴圈,也就是說~0的值為-1。想了一下也就通了:計算機是以補碼存放數字的,0二進位制的八位補碼為0000 0000,“取反”後為1111 1111,對應的就是-1的補碼了。這裡的取反加了引號,因為真正算術上的取反,數字符號位是不變的,即0000 0000的反碼是0111 1111,而補碼為0111 1111的數字是1。
與其相似的程式碼如下,經常會見到:
int c; //注意c定義為整形,因為getchar()函式返回值為
while ((c = getchar()) != EOF)
{
putchar(c);
}
getchar 等函式的返回值型別都是 int
型,當這些函式讀取出錯或者讀完檔案後,會返回 EOF.EOF 是一個巨集,標準規定它的值必須是一個 int 型的負數常量。通常編譯器都會把 EOF 定義為 -1.getchar返回的int賦值給char c的時候會發生截斷,和EOF比較時又會升級為int,可能會發生如下錯誤:
- 某些合法的字元被“截斷”了以後,恰好等於-1,導致程式在複製的過程中發生了中 斷。
- 前面的C不可能取值為EOF,導致程式產生了一個死迴圈。
標準輸入與檔案不一樣,無法事先知道輸入的長度,必須手動輸入一個字元,表示到達EOF。 Linux中,在新的一行的開頭,按下Ctrl-D,就代表EOF(如果在一行的中間按下Ctrl-D,則表示輸出"標準輸入"的快取區,所以這時必須按兩次Ctrl-D);Windows中,Ctrl-Z表示EOF。(順便提一句,Linux中按下Ctrl-Z,表示將該程序中斷,在後臺掛起,用fg命令可以重新切回到前臺;按下Ctrl-C表示終止該程序。) 那麼,如果真的想輸入Ctrl-D怎麼辦?這時必須先按下Ctrl-V,然後就可以輸入Ctrl-D,系統就不會認為這是EOF訊號。Ctrl-V表示按"字面含義"解讀下一個輸入,要是想按"字面含義"輸入Ctrl-V,連續輸入兩次就行了 EOF 意思就是 end of file!!!! 你按按CTRL+D試試