1. 程式人生 > >選擇排序---while( scanf("%d",&n)!= EOF)與getchar()簡介及其存在的問題,

選擇排序---while( scanf("%d",&n)!= EOF)與getchar()簡介及其存在的問題,

基本思想:

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.  某些合法的字元被“截斷”了以後,恰好等於-1,導致程式在複製的過程中發生了中 斷。
  2.  前面的C不可能取值為EOF,導致程式產生了一個死迴圈。
還有一種情況,就是編譯器對C語言的實現不夠規範,儘管可能會產生第一種所說的“截斷”和第二種中找不到“EOF”的情況,而且編譯器也同時將值賦值給了C,但是,編譯器裡面卻把getchar()返回的值與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試試