重写:求比指定数大且最小的“不重复数”问题

 问题:给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数”的含义是相邻两位不相同,例如1101是重复数,而1201是不重复数.

我之前写过一个(传送门:求比指定数大且最小的“不重复数”问题),里面总结了些不足的地方,就没有想去重写。

直到被 garbageMan 给教育了一番 (传送门:评playerc网友的"求比指定数大且最小的“不重复数”问题"),我才发现,写的太差劲了。

在此感谢 garbageMan 的教导。不多说,下面附上代码,有什么错误还希望大家多指点.

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

#define BCD_UINT_MAX_LENGTH (12)
/* 这里 garbageMan 指出 存在潜在的错误,两边要加上括号;(其实回家检查的时候我也发现了)
#define min(a,b)  (a) < (b) ? (a) : (b)
改成如下代码
*/
#define min(a,b) ((a) < (b) ? (a) : (b))

/* bcd unsigned integer
   little endian
*/
struct bcd_uint{
	unsigned char value[BCD_UINT_MAX_LENGTH];
	unsigned int length;
};

/*  从标准输入获得 bcd_uint */
struct bcd_uint * bcd_uint_get(struct bcd_uint * v);

/* 在指定的位置加 1. 返回进位影响的最高位的下标 */
unsigned int bcd_uint_inc(struct bcd_uint *v, unsigned int where);

/* 输出 bcd_uint */
void bcd_uint_print(struct bcd_uint v);

/*** utils ****/
/*** 获得最小不重复数 ***/
struct bcd_uint * find(struct bcd_uint v);

/* 反转字符串 */
void str_reverse(unsigned char *str, unsigned int length);

/* 交换字符*/
void exchange(unsigned char * a, unsigned char *b);

/* 得到最右边开始第一次出现重复字的最小下标的地址 */
unsigned char * get_repeat_item(unsigned char * v, unsigned int length);

int main(void)
{
	struct bcd_uint num = {{0u},0u};
	struct bcd_uint *res = NULL;

	printf("Please input Unsigned Integer : ");
	
	if (bcd_uint_get(&num) == NULL) return 1;
	
	res = find(num);
	bcd_uint_print(*res);
	
	free(res);
	return 0;	
}

void str_reverse(unsigned char *str, unsigned int length)
{
	unsigned char *last;
	if (length < 2) {
		return;
	}

	for (last = str + length -1; last > str; ++str, --last){		
		exchange(str,last);
	}
}

void exchange(unsigned char * a, unsigned char *b)
{
/* cpoint 同学指出 这个地方存在潜在的错误,比如 a=b 的时候
		*a ^= *b;
		*b ^= *a;
		*a ^= *b;
  于是,改成下面通用的代码 
*/
     unsigned char c;
     c = *a;
    *a = *b;
    *b = c;
}

struct bcd_uint * find(struct bcd_uint v)
{
	unsigned int search_length ;
	unsigned char * finded;
	unsigned char * last_finded;
	struct bcd_uint *res = (struct bcd_uint *)malloc(sizeof (struct bcd_uint));

	res->length = v.length;
	memcpy(res->value, v.value, sizeof (unsigned char) * v.length);

	bcd_uint_inc(res, 0); /* v + 1 */

	search_length = res->length;
	last_finded = res->value;

        /* 在最后一次找到重复的位置开始,查找指定的长度。 */
	while ((finded = get_repeat_item(last_finded, search_length)) != NULL){

		/* 在找到重复的位置+1,并依据进位影响的位置 设置搜索长度 */
		search_length  = bcd_uint_inc(res, finded - res->value) + 1;	
		search_length = min(search_length, res->length);
		search_length = search_length - (finded - res->value);

		last_finded = finded;
	}

	
	/* set rests as 010101010 */
	/* *last_finded will never be 0 */
	while (last_finded > res->value){		
		*(last_finded-1) = !*last_finded;
		-- last_finded;
	}

	return res;
}

unsigned char * get_repeat_item(unsigned char * v, unsigned int length)
{
	unsigned char * cur;

	if (length < 2){
		return NULL;
	}

	cur = v + length -1;
	
	while (cur > v){
		if ( *cur == *(cur - 1)){
			return cur-1;
		}
		-- cur;
	}

	return NULL;
}

struct bcd_uint * bcd_uint_get(struct bcd_uint * v)
{
	unsigned char c;
	for (v->length = 0; !feof(stdin); ++ v->length){

		/* 因为最高位可能进 1 所以 -1*/
		if (v->length > (BCD_UINT_MAX_LENGTH - 1)){
			fprintf(stderr, "The input is too long!\n");
			return NULL;
		}

		c = getc(stdin);
		if (c == '\n' || c == '\0'){
			break;
		}
		if (!isdigit(c)){
			fprintf(stderr, "Please input Unsigned Integer!\n");
			return NULL;
		}
		v->value[v->length] = c - '0';		       		
	}
	str_reverse(v->value, v->length);

	return v;
}

void bcd_uint_print(struct bcd_uint v)
{
	unsigned char * last ;

	last = v.value + v.length; 
	while(last > v.value){
		-- last;
		putchar( *last + '0');
	}
	putchar('\n');
}

unsigned int bcd_uint_inc(struct bcd_uint *v, unsigned int where)
{
	unsigned int carry ;

	for (carry = 1; carry != 0 && where < v->length; ++ where){
		v->value[where] += carry;
		carry = v->value[where] / 10;
		v->value[where] %= 10;		
	} 

	if (carry != 0){
		v->value[where] = carry;
		++ v->length;
	}
	else {
		/* 执行这里的时候 where 指向进位影响的下一个,所以减掉*/
		--where;
	}
	return where;
}

 总结:

  1. 无论写的函数在代码中是否出错,只要存在可能的错误,这个函数就是需要重写。(本质上是进行全面的测试)
  2. 定义宏是如果是完整的一体的运算就要括起来。
posted @ 2013-10-16 20:01  playerc  阅读(223)  评论(6编辑  收藏  举报
c4io.com Count Visitors
Web Counter