(大數通過輾轉取餘實現進制轉換)問題 C: 進制轉換

題目

題目描述
將一個長度最多爲30位數字的十進制非負整數轉換爲二進制數輸出。

輸入
多組數據,每行爲一個長度不超過30位的十進制非負整數。
(注意是10進制數字的個數可能有30個,而非30bits的整數)

輸出
每行輸出對應的二進制數。

樣例輸入
985
211
1126
樣例輸出
1111011001
11010011
10001100110

思路

10進制轉2進制就是,除2取餘;再用商除2取餘,一直到被除數(商)爲0,餘數的逆序就是該2進制數。
因爲是大數,所以被除數,商和餘數都要用數組存數。
輾轉取餘:一開始輸入的就是被除數,後來每一次求得的商爲被除數,一直循環直到被除數的數位爲0(即被除數爲0)

  1. 每一次大數取餘的過程:

從最高位開始除直到所有數位都除2了:
1) 這一位的被除數是上一位的餘數10(10進制)+這一位數:c = coldbase + start[i] - ‘0’;
2) 這一位商爲ans[i] = c / newbase + ‘0’;//這位商
3)這一位餘數位c = c%newbase;

  1. 最後一個餘數纔是大數除2的真正餘數
  2. 把大數商拷貝爲新的被除數,若商的最高位爲1的話被除數位數-1;拷貝時也從第2個元素開始拷貝即可
while (lennum){
			//每輾轉除2一次商就要清零一次
			memset(ans, 0, sizeof(ans));//初始化,否則無空間
			c = 0;//一開始的上一位商爲0
			
			for (int i = 0; i<lennum; i++){//從最高位開始運算,一次掃描全部並輾轉除2的過程 
				c = c*oldbase + start[i] - '0';
				ans[i] = c / newbase + '0';//這位商
				c = c%newbase;//這位餘 
			}
			if (ans[0] == '0'){
				head = 1;
				lennum--;//最高位爲0,被除數位數減一個
			}
			else
				head = 0;
			res[lenres++] = c+'0';
			strcpy(start, ans+head);//最高位若爲0則跳過
		}

注意

  1. 要在合適的地方用memset給被除數,商和餘數都初始化,否則會出現分配空間異常或保留了上一輪數據等異常情況
  2. 被除數和商的存數都是隊列存儲;但是餘數爲了存儲方便用了棧存儲,輸出時要從lenres-1開始輸出喔
  3. 輸入的數最高位可能是多個0,把讀取的大數高位前的0都消掉再填入start被除數中 ,並讓總數位減去最高位那串0的數量

AC代碼

//大數除法
//用“模2取餘法”來將一個10進制數轉換爲一個二進制數,進而可以推廣到“模n取餘法”,經其轉換爲n進制(n任意指定)。 
#include<bits/stdc++.h>
using namespace std;
int main()
{
	//把讀取的大數高位前的0都消掉再填入start被除數中 
	char str[1000];
	
	char start[1000], ans[1000], res[1000];//被除數,商,餘數
	int lennum, c;//總數位,除數暫存數(上一位的餘(c)*oldbase(這裏是10)+這一位數) 
	int oldbase = 10, newbase = 2, head,lenres;//10進制,2進制 ,最高位 ,餘數總數位
	while (scanf("%s", str) != EOF){
		lennum=strlen(str);
		for(int i=0;i<lennum;i++){
			if(str[i]!='0'||i==(lennum-1)){
				strcpy(start,str+i);
				lennum-=i;//總數位減去最高位的那串0的數量 
				break;
			}
		} 
		lenres = 0;
		memset(res, 0, sizeof(res));//初始化,否則無空間
		while (lennum){
			//每輾轉除2一次商就要清零一次
			memset(ans, 0, sizeof(ans));//初始化,否則無空間
			c = 0;//一開始的上一位商爲0
			
			for (int i = 0; i<lennum; i++){//從最高位開始運算,一次掃描全部並輾轉除2的過程 
				c = c*oldbase + start[i] - '0';
				ans[i] = c / newbase + '0';//這位商
				c = c%newbase;//這位餘 
			}
			if (ans[0] == '0'){
				head = 1;
				lennum--;//最高位爲0,被除數位數減一個
			}
			else
				head = 0;
			res[lenres++] = c+'0';
			strcpy(start, ans+head);//最高位若爲0則跳過
		}

		for (int i = lenres - 1; i >= 0; i--)
			printf("%c", res[i]);
		printf("\n") ;
		memset(start, 0, sizeof(start));//初始化
	}
	return 0;
}


延伸爲a進制轉爲b進制

每一位的暫存數被除數c = c*oldbase + a_ten(start[i]);

int a_ten(char x){
	if (isdigit(x))
		return x - '0';
	switch (x){
			case 'a':return 10;
			case 'A':return 10;
			case 'b':return 11;
			case 'B':return 11;
			case 'c':return 12;
			case 'C':return 12;
			case 'd':return 13;
			case 'D':return 13;
			case 'e':return 14;
			case 'E':return 14;
			case 'f':return 15;
			case 'F':return 15;
	}
}

每一位的商ans[i] = ten_a(c / newbase);
和每一位保留的餘數res[lenres++] = ten_a©;

char ten_a(int x){
	if (x >= 0 && x <= 9)
		return x + '0';
	switch (x)
	{
	case 10: 	return 'A';
	case 11: 	return 'B';
	case 12: 	return 'C';
	case 13: 	return 'D';
	case 14: 	return 'E';
	case 15: 	return 'F';
	}
}

AC代碼

注意:輸出0要特判

//大數除法
//用“模2取餘法”來將一個10進制數轉換爲一個二進制數,進而可以推廣到“模n取餘法”,經其轉換爲n進制(n任意指定)。 
#include<stdio.h>
#include<stdlib.h>
#include<string>
using namespace std;
int a_ten(char x){
	if (isdigit(x))
		return x - '0';
	switch (x){
			case 'a':return 10;
			case 'A':return 10;
			case 'b':return 11;
			case 'B':return 11;
			case 'c':return 12;
			case 'C':return 12;
			case 'd':return 13;
			case 'D':return 13;
			case 'e':return 14;
			case 'E':return 14;
			case 'f':return 15;
			case 'F':return 15;
	}
}
char ten_a(int x){
	if (x >= 0 && x <= 9)
		return x + '0';
	switch (x)
	{
	case 10: 	return 'A';
	case 11: 	return 'B';
	case 12: 	return 'C';
	case 13: 	return 'D';
	case 14: 	return 'E';
	case 15: 	return 'F';
	}
}
int main()
{
	//把讀取的大數高位前的0都消掉再填入start被除數中
	char str[1000];

	char t[100];
	char start[1000], ans[1000], res[1000],tt;//被除數,商,餘數,暫存數
	int lennum, c;//總數位,除數暫存數(上一位的餘(c)*oldbase(這裏是10)+這一位數) 
	int oldbase, newbase, head,lenres;//old進制,new進制 ,最高位 ,餘數總數位
	while (scanf("%s", str) != EOF){
		lennum = strlen(str);
		for (int i = 0; i<lennum; i++){
			if (str[i] != '0' || i == (lennum - 1)){
				strcpy(start, str + i);
				lennum -= i;//總數位減去最高位的那串0的數量 
				break;
			}
		}
		printf("old/new進制:");
		scanf("%d %d", &oldbase, &newbase);
		lenres = 0;
		memset(res, 0, sizeof(res));//初始化,否則無空間
		while (lennum){
			//每輾轉除2一次商就要清零一次
			memset(ans, 0, sizeof(ans));//初始化,否則無空間
			c = 0;//一開始的上一位商爲0
			
			for (int i = 0; i<lennum; i++){//從最高位開始運算,一次掃描全部並輾轉除2的過程 
				c = c*oldbase + a_ten(start[i]);
				ans[i] = ten_a(c / newbase);//這位商
				c = c%newbase;//這位餘 
			}
			if (ans[0] == '0'){
				head = 1;
				lennum--;//最高位爲0,被除數位數減一個
			}
			else
				head = 0;
			res[lenres++] = ten_a(c);
			strcpy(start, ans+head);//最高位若爲0則跳過
		}

		if (lenres == 1)//如果餘數只有一位那麼直接輸出,否則0就被跳過什麼都沒有了
			printf("%c", res[0]);
		else
			for (int i = lenres - 1; i >= 0; i--){
			tt = res[i];
			if (tt == '0'&&i == (lenres - 1))//首位的0都跳過不輸出
				lenres--;
			else
				printf("%c", tt);
		}
			
		printf("\n");
		memset(start, 0, sizeof(start));//初始化
	}
	system("PAUSE");
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章