目录
- 引言
- 题目再现
- 分析
- 思路一
- 图示理解
- 算法设计
- 编程实现
- 算法分析
- 思路二
- 图示理解
- 算法设计
- 编程实现
- 算法分析
- 思路三
- 图示理解
- 算法设计
- 翻转函数设计
- 编程实现
- 算法分析
- 程序测试(第三种为例)
引言
这道题实现起来不是很困难,但是用最优的方法去实现,还是有一定的难度,尤其是对于初学者,很难想到最优的方法。每一种方法的时间复杂度和空间复杂度都有所差别,这篇文章主要是在该问题的基础上,分析各种方法的优劣,用空间复杂度,时间复杂度来衡量一个算法好坏。
题目再现
有n个整数,使前面各数顺序向后移m个位置,最后m个数变成最前面m 个数,见图。写一函数实现以上功能,在主函数中输入n个整数和输出调整后的n个数。
分析
思路一
图示理解
算法设计
- 将arr[len-1]保存在temp;
- 将剩余数组元素,依次从后向前遍历
- 进行数据移动 arr[j+1] = arr[j] ;
- 将最后的数移动到最前面 arr[0]= temp
编程实现
void move1(int* arr, int len, int m) {//arr是数组,len是数组长度,m是需要移动的个数int temp,count = 0; //while (count < m) { //循环次数控制temp = arr[len - 1];//进行数据移动for (int j = len - 1-1; j >= 0; j--) {arr[j + 1] = arr[j];}arr[0] = temp;count++;}}
算法分析
当m为1时,需要访问n个元素,m为2时,需要访问n+n个元素,m为n时,需要访问nn个元素,访问的总次数为n+2n+3n+……nn=n(n+nn)/2,平均次数为(n+nn)/2,所以时间复杂度为O(n^2),没有开辟新的空间,所以空间复杂度为O(1)
思路二
图示理解
算法设计
- i从n-m开始遍历arr,j从0开始遍历brr
- 将arr中的元素放入brr ,循环赋值m次
- i从0开始遍历arr,j从上次遍历的位置开始遍历brr
- 将arr中的元素放入brr ,循环赋值n-m次
- brr中的值依次赋值给arr
编程实现
//#define SIZE 7void move2(int* arr, int len, int m) {int brr[SIZE] = { 0 };int j = 0;//j需要在第一次的赋值基础上再赋值,作用域比i大for (int i = len - m; i < len; i++,j++) {brr[j] = arr[i];}for (int i = 0; i < len - m; i++,j++) {brr[j] = arr[i];}for (int i = 0; i < len; i++) {arr[i] = brr[i];}}
算法分析
变量i访问了n个元素,变量j也访问了n个元素,一共访问了2n个元素,所以时间复杂度是O(n),由于开辟了n个元素的空间,所以空间复杂度就是O(n)
思路三
图示理解
算法设计
- 将整个数组翻转
- 将0~m-1的元素翻转
- 将m~len-1的元素翻转
翻转函数设计
- i=0开始遍历半个数组
- 将arr[i]与arr[len-1]交换位置
编程实现
//翻转函数void reverse(int* arr, int l_index, int r_index) {int num = r_index - l_index + 1; //该区间的元素个数int temp;for (int i = 0; i < num / 2; i++) { //i控制次数temp = arr[l_index+i];arr[l_index + i] = arr[r_index-i];arr[r_index - i] = temp;}}//交换函数void move3(int* arr, int len, int m) {reverse(arr, 0, len - 1);reverse(arr,0,m-1);reverse(arr,m,len-1);}
算法分析
翻转一次,就要访问n个元素,翻转了三次,就是3n,所以时间复杂度为O(n),没有开辟新的空间,空间复杂度为O(1)
程序测试(第三种为例)
void reverse(int* arr, int l_index, int r_index) {int num = r_index - l_index + 1; //该区间的元素个数int temp;for (int i = 0; i < num / 2; i++) { //i控制次数temp = arr[l_index+i];arr[l_index + i] = arr[r_index-i];arr[r_index - i] = temp;}}void move3(int* arr, int len, int m) {reverse(arr, 0, len - 1);reverse(arr,0,m-1);reverse(arr,m,len-1);}int main() {int arr[] = {1,2,3,4,5,6,7};int len = sizeof(arr) / sizeof(arr[0]);int m = 3; printf("翻转之前的数组:");for (int i = 0; i < len; i++) {printf("%-5d", arr[i]);}printf("\n");printf("翻转之后的数组:");move3(arr, len, m);for (int i = 0; i < len; i++) {printf("%-5d",arr[i]); }printf("\n");return 0;}
运行的结果如下