问题:给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数”的含义是相邻两位不相同,例如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;
}
总结:
- 无论写的函数在代码中是否出错,只要存在可能的错误,这个函数就是需要重写。(本质上是进行全面的测试)
- 定义宏是如果是完整的一体的运算就要括起来。