2009年4月20日 星期一

知識+ 排列


//===================================================================
// 20090418 知識 +
// http://tw.knowledge.yahoo.com/question/question?qid=1009041810620
// 發問者 : http://tw.knowledge.yahoo.com/my/my?show=AB05027385
//===================================================================


#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//------------------------------------------
int CheckShow(int n, int num, int* nn, int base) //篩選與顯示排列
{ // n:排列數值 num:排列數目 nn:不同數陣列 base:基底
int i, j, s;
int* mm = &nn[base]; //之前有配置多餘空間來做為暫存
for(i=0; i<base; i++) mm[i] = nn[i]&0xFF; //複製一份不同數的數量陣列
for(j=num, i=n, s=0; j>0; j--, s=s*base+i%base, i/=base) // 篩選迴圈
if(mm[i%base]--==0) return 0; // 篩選失敗
for(j=0, i=s; j<num; j++, i/=base) // 顯示排列
printf( "%s%d", (j==0)?"\n":",", nn[i%base]>>8 );
return 1;
}
//................
int ValuePerm(int *a, int num) // 數值法排列處理
{ // a:陣列 num:數量
int i, j, max, base, count=0;
int * nn = (int *)malloc(num*sizeof(int)*2); // 配置不同數陣列
for(i=0, j=0; i<num; i++, j=0) //不同數陣列處理與統計
{
nn[i] = a[i]<<8; // 高位元組藏放數值
while( j<i && a[i]!=a[j]) j++; //檢查重覆
nn[j]++; // 數量統計
}
for(i=0, base=0; i<num; i++) // 以不同數的數量為基底(base)
if ((nn[i]&0xFF)!=0) nn[base++]=nn[i]; // 緊湊不同數陣列
for(i=1, max=base; i<num; i++) max*=base; // 基數最大值+1
for(int n = 0; n<max; n++) // 數值處理排列 : 0~最大值(max-1)
if (CheckShow(n, num, nn, base)) count++; //篩選成功計數
free(nn); // 釋放配置空間
return count; // 傳回排列數量
}
//------------------------------------------
void swap(int *x, int *y) // 交換
{
int t=*x; *x=*y; *y=t;
}
//................
int permutation(int *a, int num, int n=0 ) // 易位法排列處理
{ // a:陣列 num:數量 n:位置
static int count;
int i, j;
if(n==0) count=0;
if(n+1==num) // 處理到末位--顯示
{
for(i=0; i<num; i++)
printf( "%s%d", (i==0)?"\n":",", a[i]);
return ++count;
}
for(i=n; i<num; i++)
{
for(j=n; j<i && a[i]!=a[j]; j++);
if (j==i) // 若尚未處理過此數
{
swap( a+i, a+n ); // 交換(易位)
permutation( a, num, n+1 ); // 後面繼續易位排列(遞迴)
swap( a+i, a+n ); // 回復易位
}
}
return count;
}
//------------------------------------------
int main() // 主程式
{
clock_t start;

int A[] = { 1, 2, 3, 4, 5, 6, 7 }; // 陣列A
int B[] = { 1, 1, 1, 1, 2, 2, 3 }; // 陣列B

int numA = sizeof(A)/sizeof(int); // A 數量
int numB = sizeof(B)/sizeof(int); // B 數量

start = clock();
int Anum = ValuePerm(A, numA); // A 數值法排列處理
printf( "\n 共 %d 種排列 費時:%f\n\n", Anum, (double)(clock()-start));

start = clock();
int Bnum = ValuePerm(B, numB); // B 數值法排列處理
printf( "\n 共 %d 種排列 費時:%f\n\n", Bnum, (double)(clock()-start));

start = clock();
Anum = permutation(A, numA); // A 易位法排列處理
printf( "\n 共 %d 種排列 費時:%f\n\n", Anum, (double)(clock()-start));

start = clock();
Bnum = permutation(B, numB); // B 易位法排列處理
printf( "\n 共 %d 種排列 費時:%f\n\n", Bnum, (double)(clock()-start));

return 0;
}
//------------------------------------------


.


這個程式應用了兩種排列方法 : 數值法易位法

易位法的觀念是每一位置都替換為不同位置的不同內容,並用遞迴的方式逐一處理下一位置.

數值法則是不使用遞迴,而是將陣列內容處理成連續數值,由連續數值中進行篩選出符合的數值.
數值法會以等於或大於(取2冪可加快運算速度)陣列內不同內容的數量來當作連續數值基底,
因此所得的連續數值的上限值將是 (數值基底^陣列內容數量)-1 ;故數值法不宜處理大數量.
且要透過篩選, 所以速度會較 易位法 來的慢, 它特點是避開了遞迴的使用.

2009年4月18日 星期六

知識+ 某數A的B進制

//=================================================================
// 20090411 知識+
// http://knowledge.yahoo.com.tw/question/question?qid=1609041106275
// 發問者: http://tw.knowledge.yahoo.com/my/my?show=AB04702665
//=================================================================

#include <stdio.h>
#include <stdlib.h>

int main()
{
int A, B;
unsigned int n; // 用正整數 n 來進行轉換處理
char str[33]; // 這足夠存放32位元整數的轉換字串了!!
while(1) // 循環執行, 若要單次執行, 可移除這行
{
char * p = str+sizeof(str)-1; // 設p指標指到存放字串位置的末端
printf("\n請輸入數目(%d~%d): ", 1<<31, (1u<<31)-1 ); //最小值與最大值
scanf("%d", &A);
printf("請輸入要轉換的進制數(2~36,超出範圍將結束): ");
scanf("%d", &B);
if (B<2 || B>36) return 0;
*p = '\0'; // 字串最末端先放 0 (為字串的結尾)
for(n=(A>0)? A: -A; n>0; n/=B) // 用迴圈進行進制轉換(若A為負數,改取正數)
*--p = (n%B<10)? '0'+n%B: 'A'+n%B-10; //將p逐位往前,並逐一存放轉換字元
if (A==0) *--p = '0'; // 若輸入的A為0, 就在字串中放0
else if (A<0) *--p = '-'; // 若輸入的A為負數, 則轉換後的字串前也補 '-'
printf( "%d的%d進制表示為: %s\n", A, B, p);
}
return 0;
}

//==下面程式碼是改用陣列索引的方式, 並用位元填滿的方式處理正負號(補數)

#include <stdio.h>
#include <stdlib.h>

const int bits = sizeof(int)*8;

int main()
{
int A, B, p;
unsigned int n, m; // 用正整數 n 來進行轉換處理
char str[bits+1]; // 這足夠存放int整數的轉換字串了!!
while(1)
{
p = sizeof(str)-1; // 設索引指到存放字串位置的末端
printf("\n請輸入數目(%d~%d): ",1<<(bits-1), (1u<<(bits-1))-1 );
scanf("%d", &A);
printf("請輸入要轉換的進制數(2~36,超出範圍將結束): ");
scanf("%d", &B);
if (B<2 || B>36) return 0;
str[p] = '\0'; // 字串最末端放 0 (為字串的結尾)
for(n=A, m=-1; m>0; n/=B, m/=B) // 用迴圈進行進制轉換
str[--p] = (n%B<10)? '0'+n%B: 'A'+n%B-10; //將p逐位往前,並逐一存放轉換字元
printf( "%d的%d進制(%d位元)表示為: %s\n", A, B, bits, &str[p]);
}
return 0;
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~






2009年4月7日 星期二

知識+ 大陣列中bit處理(可跨byte)


//===================================================================
// 20090331 知識 +
// http://tw.knowledge.yahoo.com/question/question?qid=1509033101375
// 發問者 : http://tw.knowledge.yahoo.com/my/my?show=AE03178958
//===================================================================

#include <stdio.h>
#include <stdlib.h>

#pragma pack(1)
struct BYTE
{
unsigned char Byte;
unsigned int getBits(unsigned int i, unsigned char l=1 )
{
unsigned int rtn = 0;
if (l>32l==0) return 0;
int n=i/8;
int b=i%8;
unsigned char * p = (unsigned char *)((&Byte)+n);
while(l-->0)
{
rtn = ((unsigned int)(((*p)>>(7-b))&1))<<l;
if (++b==8){ b=0; p++;}
}
return rtn;
}
void setBits(unsigned int i,unsigned int d, unsigned char l=1)
{
if (l>32l==0) return;
int n=i/8;
int b=i%8;
unsigned char * p = (unsigned char *)((&Byte)+n);
while(l-->0)
{
if ((d>>l)&1) *p = 0x80>>b;
else *p &= ~(0x80>>b);
if (++b==8){ b=0; p++;}
}
}
};

int main()
{
BYTE a[32];

printf( "\n a[] size = %d, BYTE size= %d\n", sizeof(a), sizeof(BYTE));
for(int i=0; i<30; i++)
a[i].Byte=0;

for(int i=0; i<240; i++)
a[0].setBits(i,(i%3==0)?1:0);

printf ("\nDump Buffer:\n");
for(int i=0; i<30; i++)
printf("0x%02X%c",a[i].Byte, (i%10==9)? '\n': ' ');

//
printf ("\nSet & Get:");
for(int i=0; i<240; i+=3)
{
a[0].setBits(i, (i/3%8), 3);
printf("%cx%01X", (i%60==0)? '\n': ' ', a[0].getBits(i,3) );
}

printf ("\n\nDump Buffer:\n");
for(int i=0; i<30; i++)
printf("0x%02X%c",a[i].Byte, (i%10==9)? '\n': ' ');
return 0;
}

//=============================================================================

知識+ 迴文判斷


//===================================================================
// 20090406 知識 +
// http://tw.knowledge.yahoo.com/question/question?qid=1509040602278
// 發問者 : http://tw.knowledge.yahoo.com/my/my?show=AF03564771
//===================================================================

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 尋找可接受字元: s-字串 n-索引指標 d-索引移動方向(遞增或遞減)
char find(char *s, int *n, int d)
{
while(*n>=0 && s[*n]!=0)
{
if ((s[*n]|0x20)>='a' && (s[*n]|0x20)<='z') //大小寫字母
return (s[*n]|0x20); // 回傳為小寫字元

//...可視需求在這增加接受判斷字元符號的程式碼, 如下列的數字:
if (s[*n]>='0' && s[*n]<='9') //若要忽略數字, 請移除這兩行!!
return s[*n]; // 回傳數字字元

*n += d; // 將索引遞增(或遞減), 來搜尋下一可接受字元
}
return d; //找不到可接受字元, 回傳遞增值來區分
}

int main()
{
char str[100];
int len, i, j;
while(1)
{
printf("\nEnter a string: ");
gets(str);
len = (int)strlen(str);
if (len<2) break; //若輸入小於兩個字則離開迴圈.

printf("The reverse string: ");
for(i = len-1;i >= 0;i--)
printf("%c",str[i]);

for(i=0, j=len-1; j>i; i++, j--) // i從頭找, j從尾找
if (find(str, &i, 1)!=find(str, &j, -1))
break; //若發現字元不合, 則跳離迴圈..
printf( "\n\"%s\" is%s a palindrome\n",
str, (j>i)?" not": "");
}
return 0;
}

//執行結果 :
//
//Enter a string: Gary knits a stinky rag.
//The reverse string: .gar yknits a stink yraG
//"Gary knits a stinky rag." is a palindrome
//
//Enter a string:

知識+ 直譯運算

//===================================================================
// 20090402 知識 +
// http://tw.knowledge.yahoo.com/question/question?qid=1609040211054
// 發問者 : http://tw.knowledge.yahoo.com/my/my?show=AF04167627
//===================================================================

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

double var[26] = {0};
char cd[256];
int cp;

char Op[]={ 0, '*', '/', '+', '-' };
int On[]={ 0, 0x60, 0x61, 0x50, 0x51 };
int lev=0;

int getN(double *n)
{
*n = 0;
int x=1;
int e = -5;
double d = 1.;
if (cd[cp]=='-') { cp++; x=-1; };
for( ;cd[cp]>='0' && cd[cp]<='9' || cd[cp]=='.'; cp++)
{
if (cd[cp]!='.')
{
e=0;
if (d==1.)
{
*n = *n*10+(cd[cp]&0x0F);
continue;
}
*n += d*(cd[cp]&0x0F);
}
else if (d<1) return -4;
d /= 10.;
}
if (x<0) *n *= -1.;
return e;
}

int get( double *n, int *op )
{
int i;
while ( cd[cp]=='(' || cd[cp]==' ')
if (cd[cp++]=='(') lev++;
int p=cp;
if ( (cd[cp]|0x20)>='a' && (cd[cp]|0x20)<='z')
{ i=(cd[cp++]|0x20)-'a'; *n=var[i]; }
else if ((i=getN(n))<0) return i;
while (cd[cp]==')' || cd[cp]==' ')
if (cd[cp++]==')')
if (--lev<0) return -8;
for(i=4; i>=0; i--) if (cd[cp]==Op[i]) break;
if (i<0) return -6;
if (i==0 && lev>0) return -7;
*op=(lev<<8) + On[i];
cp++;
return 0;
}

int oper( double *n1, int *o1 )
{
double n2;
int o2;
int e=get( &n2, &o2);
while( !e && (o2>>4) > ((*o1)>>4) ) e=oper( &n2, &o2 );
if (e) return e;
switch ( (*o1)&0xFF )
{
case 0: *n1=n2; return 0;
case 0x60: *n1*=n2; break;
case 0x61: if (n2) *n1/=n2; else printf("/0錯誤!!\n"); break;
case 0x50: *n1+=n2; break;
case 0x51: *n1-=n2; break;
default: return -3;
}
*o1=o2;
return 0;
}

int parse()
{
char ic[2][8] = { "quit", "print" };
int c=3;
int v=-1;
int p=0;
while(cd[p]==' ')p++;
cp=p;
while((cd[cp]|0x20)>='a'&& (cd[cp]|0x20)<='z')
cd[cp++] |= 0x20;
if (cp-p>1) // 命令
{
cd[cp++] = '\0';
for(c=1; c>=0 && strcmp( &cd[p], ic[c])!=0; c--);
if (c!=1) return c; // 0: 離開 -1: 命令錯誤
}
else if(cp-p==1) // 變數
{
v = cd[p]-'a';
while(cd[cp]==' ')cp++;
if (cd[cp++]!='=') return -2;
c=2;
}
else return (strlen(cd)==0)?3:-1;
int op=0;
double n=0.;
lev = 0;
p = oper(&n, &op);
if (p<0) return p;
if(c==1) printf("%f\n", n);
if(v>=0) var[v] = n;
return c; // 2:指定敘述 1:顯示敘述
}

int main()
{
int c=1;
printf("\n# Welcome!!\n");
while(c!=0)
{
printf("]");
gets(cd);
c = parse();
if (c<0) printf("*** (%d)Error!!\n", c);
}
printf("# Bye.\n");
return 0;
}