数组的两个练习
左移右移
假设有数组[1,2,3,4,5]
- 左移表示数组元素向左移动1位,移出的元素放入末端,即[2,3,4,5,1]
- 右移表示数组元素向右移动1位,移出的元素进入首部,即[5,1,2,3,4]
实现时应该注意
- 数组存在只有1个元素的情形
- 执行位移时,当前位置的值会被重写,我们需要先建立此值的拷贝。
- 我们的实现只针对int类型
在开始编写程序前,我们先做一个简单的规划,
- 左移与右移应该独立为函数,而不是只完成一次操作的功能。
- 为了方便验证结果,我们需要一个打印数组的函数。
为此,我们可以先列出函数原型。
void print_array(int arr[], int size);
void left_shift_array(int arr[], int size);
void right_shift_array(int arr[], int size);
接下来,我们逐个函数编写程序:
void print_array(int arr[], int size)
{
printf("[");
for (int i = 0; i < size; i++)
printf( i < (size - 1) ? "%d, " : "%d", arr[i]);
printf("]\n");
}
print_array()使用条件运算符控制格式符,为每个非最后元素追加一个','分隔符,整个数组以[]包含。
void left_shift_array(int arr[], int size)
{
// 数组只有一个元素时,不需要处理
if (size == 1)
return;
// 保存第一个元素的拷贝
int first = arr[0];
// 将后面的元素逐个向前移动1位
for (int i = 1; i < size; i++)
arr[i - 1] = arr[i];
// 第一个元素放到数组尾部
arr[size - 1] = first;
}
左移函数left_shift_array()已经注释的很详细了,右移的编写与之类似,只需要反向进行即可。
void right_shift_array(int arr[], int size)
{
if (size == 1)
return;
int last = arr[size - 1];
for (int i = size - 1; i > 0; i--)
arr[i] = arr[i - 1];
arr[0] = last;
}
最后我们编写主函数,驱动我们的代码即可。
int main()
{
int nums[] = { 1, 2, 3, 4, 5, 6 };
print_array(nums, 6);
printf("\nleft shift:\n");
left_shift_array(nums, sizeof(nums) / sizeof(int));
print_array(nums, 6);
left_shift_array(nums, sizeof(nums) / sizeof(nums[0]));
print_array(nums, 6);
printf("\nright shift:\n");
right_shift_array(nums, sizeof(nums) / sizeof(int));
print_array(nums, 6);
right_shift_array(nums, sizeof(nums) / sizeof(nums[5]));
print_array(nums, 6);
return 0;
}

何年何月
也许我们对今天是这一年中的第x天感兴趣,同样可以编写程序来求解。首先我们考虑一下月份天数的存储设计,数组是首选:
int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
下标0对应1月份的天数,这个偏差不是大问题,但如果让下标与月份一一对应,可能更优雅。这里我们为数组分配13个空间,0索引处不用,这样days[1]就与1月的天数相对应了。
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
另一种设计就是,要不要存储月份天数累加值?这种策略下,查询会很简单;而使用之前的方法,则需要一个循环累加求值。
int days[13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
days[7] + 26 = 212 + 26 = 238 // 当查询8月26日时的表达
这里,我们选择第二种方式存储月份信息。函数is_leap_year()判断传入的年份是否为闰年,这样一年的2月份会有29天。
int days_in_month(int year, int month)
{
int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month == 2 && is_leap_year(year))
return 29;
else
return days[month];
}
bool is_leap_year(int year)
{
return (year % 4 == 0 && year % 100 != 0) ||
(year % 400) == 0;
}
然后就是累加计算天数的部分:
int date_to_days(int year, int month, int day)
{
int days = day;
for (int m = 1; m < month; m++)
{
days += days_in_month(year, m);
}
return days;
}
最后编写主程序将它们驱动起来。
int main()
{
printf("2000-05-02: %d\n", date_to_days(2000, 5, 2));
printf("1956-11-30: %d\n", date_to_days(1956, 11, 30));
printf("2021-08-26: %d\n", date_to_days(2021, 8, 26));
return 0;
}
