当前位置: 首页 > news >正文

C 408—《数据结构》算法题基础篇—数组(通俗易懂)

目录

Δ前言

一、数组的合并

        0.题目:

        1.算法设计思想:

        2.C语言描述:

        3.算法的时间和空间复杂度 : 

二、数组元素的倒置

        0.题目 : 

        1.算法设计思想 : 

        2.C语言描述 : 

        3.算法的时间和空间复杂度 : 

三、数组中特定值元素的删除

        0.题目 : 

        1.算法设计思想 : 

        2.C语言描述 : 

        3.算法的时间和空间复杂度 : 

四、数组中值位于某一区间的元素的删除

        0.题目 : 

        1.算法设计思想 : 

        2.C语言描述 : 

        3.算法的时间和空间复杂度 : 

五、数组的去重

        0.题目 : 

        1.算法设计思想 : 

        2.C语言描述 : 

        3.算法的时间和空间复杂度 : 

六、数组中两个子数组的位置互换

        0.题目 : 

        1.算法设计思想 : 

        2.C语言描述 : 

        3.算法的时间和空间复杂度 : 

七、数组元素的循环移动 [2010真题]

        0.题目 : 

        1.算法设计思想 :

        2.C语言描述 : 

        3.算法的时间和空间复杂度 : 

Δ总结


Δ前言

  • 408应试的角度来看,算法题主要分为四部分——①线性表(包括数组和链表);②二叉树;③图;④查找。本篇博文主要讲数组相关基础算法
  • 博文中涉及到的题目全部参考自《王道数据结构考研复习指导》《竟成408考研复习全书》。
  • 注意事项——①点击文章侧边栏目录或者文章开头的目录可以进行跳转。所有题目都符合408算法题的题目格式,即第一问算法设计思想、第二问C语言描述该算法、第三问计算该算法的时空复杂度。
  • 良工不示人以朴,up所有文章都会适时补充完善。大家如果有问题都可以在评论区进行交流或者私信up。感谢阅读!

一、数组的合并

        0.题目:

        现有两个有序的并且是升序的顺序表,要求将这两个顺序表合并为一个新的有序顺序表,并且合并后整个顺序表仍然保持升序,实现该算法的函数需要有返回结果。请设计一个算法来实现上述操作,用C语言描述该算法,并且计算出该算法的时间复杂度和空间复杂度。

        1.算法设计思想:

        “两个有序表合并为一个新的有序表”是一个经典的算法问题。

        它的算法思想是——假设两个升序表分别为a和b,合并后的新的顺序表为c,从头到尾依次比较a和b中的元素,并把更小的那个元素放在c中,直到合并完毕

        若顺序表a中的元素已经全部复制到了新的顺序表c中,而顺序表b中此时还有未比较的元素,说明顺序表b要比顺序表a更长,且顺序表b中剩余的元素都比新顺序表c中已经有的元素更大,此时,只需要将顺序表b中剩余的元素全部复制到c中即可;反之亦然。

        那么,具体用代码怎么实现呢?

        我们可以用三个变量i, j, k分别表示顺序表a, b, c的下标,并且i, j, k的初始值都为0,如果a[i] <= b[j],说明a顺序表的第一个元素要比b顺序表的第一个元素更小,所以此时要将这个更小的元素放到新的顺序表中,即“c[k++] = a[i++];”,既传递了值又移动了下标。如果判断不成立,说明b顺序表的第一个元素更小,那我们就要执行“c[k++] = b[j++];”,之后元素的判断都符合这个逻辑。当然,这只是执行的思路,具体的实现我们还可以加入对结构体的数据定义,还可以通过指针变量得到合并后的新的顺序表,请看下文具体的代码实现。

        2.C语言描述:

                完整代码如下:(注意看注释)

# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>       //or "typedef enum { false, true } bool;"# define MAX_SIZE 100//定义数据结构(Sequential List)
typedef struct SqList {int data[MAX_SIZE];     //data数组存放顺序表中的元素int length;             //length表示顺序表当前存放的元素的个数int capacity;           //capacity表示预分配的数组容量,即最多可存放的元素个数
} SqList;   //函数声明
void initialize(SqList * L);
bool mergeTwo(SqList a, SqList b, SqList * c);int main(void) {SqList a,b,c;initialize(&a);initialize(&b);initialize(&c);//给出两个升序的顺序表,用于测试该算法int array_a[] = {1,2,5,7,9,11,660,880};int array_b[] = {1,3,4,6,10};for (int i = 0; i < 8; ++i) a.data[i] = array_a[i];for (int j = 0; j < 5; ++j) b.data[j] = array_b[j];a.length = 8;b.length = 5;bool point = false;point = mergeTwo(a,b,&c);printf("合并成功了吗———%s\n",point ? "Yes" : "No");printf("合并后的数组是———");for (int i = 0; i < c.length; ++i) {printf("%d ",c.data[i]);}printf("合并后数组的长度是:%d\n",c.length);return 0;
}//初始化数组的方法
void initialize(SqList * L) {L->length = 0;L->capacity = MAX_SIZE;
}//实现“顺序表合并”算法的核心方法(通过指针传递,可以让我们操作合并后的数组)
bool mergeTwo(SqList a, SqList b, SqList * c) {int i = 0, j = 0, k = 0;                //i,j,k分别用于表示a,b,c数组的下标if ((a.length + b.length) > c->capacity) {return false;                       //如果新数组的容量不足以容纳合并后的所有元素,则直接返回false。}while (i < a.length && j < b.length) {  //只要顺序表a和b中还有元素没有合并完成,就继续进行合并if (a.data[i] <= b.data[j]) {c->data[k++] = a.data[i++];} else {c->data[k++] = b.data[j++];}}while (i < a.length) {                  //如果a中还有剩余的元素,就直接复制到c中c->data[k++] = a.data[i++];}while (j < b.length) {c->data[k++] = b.data[j++];         //如果b中还有剩余的元素,就直接复制到c中}c->length = k;                          //最后别忘记设置新数组的长度return true;
}

                运行结果 : 

        3.算法的时间和空间复杂度 : 

        (1) 时间复杂度:

        实现合并算法的第一个while循环最多执行 n + m 次,因为每次迭代,i 或 j 都会增加 1,直到其中一个数组被完全处理;后两个while循环只有一个会执行,并且最多执行 n 或 m 次。所以算法的时间复杂度是O(m+n) + O(max{m,n}) = O(m+n)。
        (2) 空间复杂度:

        因为我们创建了一个新的数组来存储合并后的结果,其大小等于两个输入数组的总长度。所以空间复杂度也为O(m+n)。


二、数组元素的倒置

        0.题目 : 

        有一个长度为n的顺序表L,现要求将顺序表L的所有元素进行倒置。请设计一个算法来实现上述操作,用C语言描述该算法,并且计算出该算法的时间复杂度和空间复杂度。

        1.算法设计思想 : 

        所有元素进行倒置,也就是数组的头尾元素依次进行交换,数组第一个元素和最后一个元素进行交换,数组第二个元素和倒数第二个元素进行交换,以此类推,如果数组中有偶数个元素,正好两两交换完成;如果数组中有奇数个元素,那么中间那个元素就不会被操作。

        那么,如何实现交换操作呢?

        借助临时变量temp来实现。比方说用i 表示数组下标,则需要执行“temp = array[i]; array[i] = array[n-1-i]; array[n-1-i] = temp;”来实现数组首尾元素的交换;交换完成后,需要移动下标i直到数组中间的那个元素,可以借助for循环来实现。(PS : n是数组的长度,所以n - 1就是数组最后一个元素的下标。

        2.C语言描述 : 

                完整代码如下:(注意看注释) 

# include <stdio.h>
# include <stdlib.h># define MAX_SIZE 100//定义数据结构(Sequential List)
typedef struct SqList {int data[MAX_SIZE];int length;int capacity;
} SqList;//函数声明
void initialize(SqList * L);
void reverseArray(SqList * L);int main(void) {SqList array;initialize(&array);//给出一个具体的顺序表,用于测试该算法int array_demo[] = {1,2,3,5,7,9,11};for (int i = 0; i < 7; ++i) array.data[i] = array_demo[i];array.length = 7;reverseArray(&array);for (int i = 0; i < 7; ++i) printf("倒置后的数组的第%d个元素是%d\n",(i+1),array.data[i]);return 0;
}//初始化数组的方法
void initialize(SqList * L) {L->length = 0;L->capacity = MAX_SIZE;
}//实现“数组倒置”算法的核心方法
void reverseArray(SqList * L) {int i, temp = 0;                    //i作为数组的元素下标,temp作为实现交换操作的临时变量int n = L->length;for (i = 0; i < n / 2; ++i) {       //尤其注意控制条件语句“i < n / 2”,若误写成了“i < n”,数组就会被倒置两次。temp = L->data[i];L->data[i] = L->data[n - 1 - i];L->data[n - 1 - i] = temp;}
}

                运行结果 : 

        3.算法的时间和空间复杂度 : 

        (1) 时间复杂度

        实现倒置算法的核心方法reverseArray中,尽管for循环只执行了n/2次,但for循环的执行次数与问题规模n成正比例关系,所以时间复杂度为O(n)。这是数组倒置最优的时间复杂度,因为我们至少要将数组中的每一个元素都遍历一次。
        (2) 空间复杂度

        由于我们只使用了i,temp,n这几个单独的变量来辅助算法的实现,它们不依赖于问题规模n,所以该算法的空间复杂度是O(1),即该算法是“原地工作”的。综合来看,这是一个高效率的算法。


三、数组中特定值元素的删除

        0.题目 : 

        有一个长度为n的顺序表L,要求删除该顺序表中所有值为5的元素。请设计一个算法来实现上述操作,用C语言描述该算法,并且计算出该算法的时间复杂度和空间复杂度。

        1.算法设计思想 : 

        注意,顺序表中删除特定值的元素与链表中有明显区别。如果是在链表中删除指定值的元素,我们只需要修改被删除结点的前一个结点的指针,使其指向被删除结点的后一个结点,就可以在逻辑上删除这个结点,然后只需要调用free函数释放掉它所占用的内存空间即可。但是在顺序表中,由于顺序表是在一片连续的地址空间中,所以当我们逻辑上删除特定值的元素后,必须向前移动后面的元素来填补空缺,使其仍是一个连续的完整的顺序表

        那么,怎么能够既删除掉指定值的结点,同时又可以把后面的元素往前移动呢?(这么做有最优的时间复杂度)

        我们可以用一个辅助变量count来记录被删除的元素的个数,然后让后面的元素向前移动count个单位,最后让数组的长度减少count。比方说,一个数组仅有5个元素,分别是{1,2,5,5,3};,在for循环中,如果当前元素的值等于5,我们就让count的值自增1,这样在遍历到第5个元素3时,count已经是2了,这时让元素3向前移动2个单位,同时让数组长度减2,刚好得到我们想要的数组{1,2,3}。

        2.C语言描述 : 

                完整代码如下:(注意看注释) 

# include <stdio.h>
# include <stdlib.h># define MAX_SIZE 100//定义数据结构
typedef struct SqList {int data[MAX_SIZE];int length;int capacity;
} SqList;//函数声明
void initialize(SqList * L);
int deleteByValue(SqList * L, int e);int main(void) {SqList array;initialize(&array);//给出一个具体的顺序表,用于测试该算法int array_demo[] = {1, 5, 11, 5, 80, 5, 5, 141};for (int i = 0; i < 8; ++i) array.data[i] = array_demo[i];array.length = 8;int count = deleteByValue(&array, 5);printf("数组中被删除的值为5的结点一共有%d个~\n",count);printf("删除值为5的元素后, 数组为:");for (int i = 0; i < array.length; ++i) printf("%d ",array.data[i]);return 0;
}void initialize(SqList * L) {L->length = 0;L->capacity = MAX_SIZE;
}int deleteByValue(SqList * L, int e) {if (L == NULL || L->length == 0) {return -1;}int count = 0;                              //count变量用来记录被删除的结点的个数for (int i = 0; i < L->length; ++i) {if (L->data[i] == e) {                   //每遇到一个值为e的元素,就对count进行自增count++;} else {                                //如果当前元素的值不为e,就向前移动count个单位L->data[i - count] = L->data[i];}}L->length = L->length - count;              //最后别忘记更新数组的长度return count;
}

                运行结果 : 

        3.算法的时间和空间复杂度 : 

        (1) 时间复杂度

        在deleteByValue方法中,我们只遍历了一次顺序表,for循环内语句的执行次数与问题规模n成正比例关系,所以时间复杂度为O(n)。
        (2) 空间复杂度

        只使用了几个辅助变量,所以空间复杂度为O(1),即该算法是“原地工作”的。综合来看,这是一个解决该类问题的最佳算法。


四、数组中值位于某一区间的元素的删除

        0.题目 : 

        现有一顺序表,要求删除顺序表中所有值位于[a,b]区间的元素(a < b),若区间表示范围不合理或顺序表为空,则显示出错误信息并退出运行。请设计一个算法来实现上述操作,用C语言描述该算法,并且计算出该算法的时间复杂度和空间复杂度。

        1.算法设计思想 : 

        同上文中数组中特定值元素的删除类似,我们可以用一个辅助变量count来记录被删除的元素的个数,然后让后面的元素向前移动count个单位,最后让数组的长度减少count。然后我们只需要修改一下if条件语句的判断条件就行。

        2.C语言描述 : 

                完整代码如下:(注意看注释)  

# include <stdio.h>
# include <stdlib.h># define MAX_SIZE 100//定义数据结构
typedef struct SqList {int data[MAX_SIZE];int length;int capacity;
} SqList;//函数声明
void initialize(SqList * array);
int deleteByRange(SqList * array, int a, int b); int main(void) {SqList array;initialize(&array);//给出一个具体的顺序表,用于测试该算法(测试删除值位于[3.5]区间的元素)int array_demo[] = {1, 2, 3, 4, 4, 5, 5, 11, 999, 11, 5};for (int i = 0; i < 11; ++i) array.data[i] = array_demo[i];array.length = 11;int count = deleteByRange(&array, 3, 5);printf("数组中一共被删掉了%d个元素\n", count);printf("删除值位于[3,5]的元素后,数组剩余元素如下:\n");for (int i = 0; i < array.length; ++i) printf("%d ",array.data[i]);return 0;
}void initialize(SqList * array) {array->length = 0;array->capacity = MAX_SIZE;
}int deleteByRange(SqList * array, int a, int b) {if (a > b) {printf("请输入正确的区间~");exit(0);return -1;}if (array == NULL || array->length == 0) {printf("请传入合法的数组~");}int count = 0;for (int i = 0; i < array->length; ++i) {if (array->data[i] >= a && array->data[i] <= b) {count++;} else {array->data[i - count] = array->data[i];}}array->length = array->length - count;return count;
}

                运行结果 :

        3.算法的时间和空间复杂度 : 

        (1) 时间复杂度

        在deleteByRange方法中,我们只遍历了一次顺序表,for循环内语句的执行次数与问题规模n成正比例关系,所以时间复杂度为O(n)。
        (2) 空间复杂度

        只使用了几个辅助变量,所以空间复杂度为O(1),即该算法是“原地工作”的。综合来看,这是一个解决该类问题的最佳算法。


五、数组的去重

        0.题目 : 

        已知某有序表中存在值重复的元素,要求从中删除所有值重复的元素,使表中所有元素的值均不相同。请设计一个算法来实现上述操作,用C语言描述该算法,并且计算出该算法的时间复杂度和空间复杂度。

        1.算法设计思想 : 

        首先注意这个算法的前提——有序表。显然,如果要对一个有序表去重,那么有序表中自然而然就有两种元素——具有重复值的元素和不重复的元素。类似于上文“数组中特定值元素的删除” 和 “数组中值位于某一区间的元素的删除”,我们只要用不重复的元素覆盖掉重复的元素,就可以在逻辑上完成有序顺序表的去重。当然我们希望在一次遍历过程就完成这件事,这样可以达到O(n)的时间复杂度,这是这类问题的最优时间复杂度。

        那么,我们怎么利用代码来实现呢?

        我们可以使用两个辅助变量uniqueIndex和currentIndex,这是两个循环变量,也是两个下标,其中uniqueIndex用于指向已经保存的元素,它的初始值是0;而currentIndex表示当前指向的元素,也就是需要进行比较的第一个元素,它的初始值是1,因为当下标指向数组的第一个元素时,第一个元素一定不会重复,它前面已经没有其他元素了,所以第一个元素不需要进行比较。比较这两个下标指向的元素,如果当前指向的元素和已经保存的元素不相同,说明当前元素也需要被保存,这时,要先移动uniqueIndex指针(++uniqueIndex),再进行元素的覆盖(array->data[++uniqueIndex] = array->data[currentIndex];)。如果相同,说明当前指向的元素是重复的,不需要进行操作,直接进行下一次循环即可。

        2.C语言描述 : 

                完整代码如下:(注意看注释)  

# include <stdio.h>
# include <stdlib.h># define MAX_SIZE 100//定义数据结构
typedef struct SqList {int data[MAX_SIZE];int length;int capacity;
} SqList;//函数声明
void initialize(SqList * array);
int removeDuplicates(SqList * array);int main(void) {SqList array;initialize(&array);//给出一个具体的有序表,用于测试该算法int array_demo[] = {1, 2, 2, 3, 4, 5, 5, 5, 11, 19, 23, 23, 55, 141};for (int i = 0; i < 14; ++i) array.data[i] = array_demo[i];array.length = 14;int count = removeDuplicates(&array);printf("被删除的重复元素一共有%d个\n",count);printf("去重后的有序表如下——\n");for (int i = 0; i < array.length; ++i) printf("%d ",array.data[i]);return 0;
}void initialize(SqList * array) { array->length = 0;array->capacity = MAX_SIZE;
}int removeDuplicates(SqList * array) {if (array->length == 0 || array == NULL) return -1;int count = 0;      //count变量用于记录被删除的元素的个数。/*(1) uniqueIndex下标记录已经保存的元素;currentIndex下标记录当前指向的元素。(2) uniqueIndex初始值为0,指向数组第一个元素;currentIndex初始值为1,指向数组第二个元素。*/for (int uniqueIndex = 0,currentIndex = 1; currentIndex < array->length; ++currentIndex) { /*如果当前指向的元素和已经保存的元素不相同,(注意现在是一个有序表)则当前元素也需要保存,uniqueIndex下标和currentIndex下标都会向右移动;否则不保存当前元素,只移动currentIndex下标。   */if (array->data[currentIndex] != array->data[uniqueIndex]) {array->data[++uniqueIndex] = array->data[currentIndex];      //先移动下标,后覆盖元素。} else {count++;}}array->length = array->length - count;return count;
}

                运行结果 : 

        3.算法的时间和空间复杂度 : 

        (1) 时间复杂度 : 

        一次遍历就实现了有序表的去重,所以该算法的时间复杂度是O(n)。
        (2) 空间复杂度

        只使用了几个临时的辅助变量,所以该算法的空间复杂度是O(1)。也就是说该算法是“原地工作”的,显然这是解决该类问题最优的算法。


六、数组中两个子数组的位置互换

        0.题目 : 

        已知在一个一维数组A[m+n]中,依次存放有两个顺序表(a1, a2, ..., am) 和 (b1, b2, ..., bn),现在要求将这两个顺序表的位置进行互换,即将(b1, b2, ..., bn) 放在 (a1, a2, ..., am)的前面。请设计一个算法来实现上述操作,用C语言描述该算法,并且计算出该算法的时间复杂度和空间复杂度。

        1.算法设计思想 : 

        就是把{a1,a2,...,am,b1,b2,...,bn} 变成 {b1,b2,...,bn,a1,a2,...,am},也就是说两个子数组的顺序换了,但是子数组内部依然保持着原来的顺序。我们要将这个题目和上文“数组元素的倒置”联系起来。如果一开始的数组是{am,..a2,a1,bn,...,b2,b1},那么我们是不是只需要将这个数组倒置一次就变成了我们想要的数组。但是怎么才能利用这个过渡的数组来完成算法呢?先将两个子数组分别倒置,再将整个数组进行一次倒置,就可以得到我们最终想要的数组。

        那么,代码怎么实现?

        可知我们一共需要进行三次“倒置”,前两次是分别将两个子数组倒置,后一次是直接将整个数组进行倒置。所以我们可以利用上文中“数组元素的倒置”的算法,通过调整传入的形参,调用三次该算法,即可成功互换两个子数组的位置。

        2.C语言描述 : 

                完整代码如下:(注意看注释)  

# include <stdio.h>
# include <stdlib.h># define MAX_SIZE 100//定义数据结构
typedef struct SqList {int data[MAX_SIZE];int length;int capacity;
} SqList;//函数声明
void initialize(SqList * array);
void reverse(SqList * array, int start, int end);
void reverseTwoSubArray(SqList * array, int formerLength, int latterLength);int main(void) {SqList array;initialize(&array);//给出一个具体的顺序表,用于测试该算法int array_demo[] = {11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7};for (int i = 0; i < 12; ++i) array.data[i] = array_demo[i];array.length = 12;printf("逆置两个子数组前,整个数组的情况如下———\n");for (int i = 0; i < 12; ++i) printf("%d ", array.data[i]);reverseTwoSubArray(&array, 5, 7);printf("\n逆置两个子数组后,整个数组的情况如下————\n");for (int i = 0; i < 12; ++i) printf("%d ", array.data[i]);return 0;
}/**function : initialize(as its name)parameter list : array---the arraylist which you want to initialize*/
void initialize(SqList * array) {array->length = 0;array->capacity = MAX_SIZE;
}/**fucntion : reverse(just a certain part of an array)parameter list : (1)array---operated arraylist;(2)start---the index of the opening element of the array;(3)end---the index of the ending element of the array;*/
void reverse(SqList * array, int start, int end) {int temp = 0;int subArrayLength = end - start;for (int i = 0; i < subArrayLength / 2; ++i) {temp = array->data[start];array->data[start] = array->data[end - i];array->data[end - i] = temp;start++;}
}/**function : reverseTwoSubArray(which will invoke the reverse function above)parameter list : (1)array---operated arraylist;(2)formerLength---the former subarray's length, logically;(3)latterLength---the latter subarray's length, also logically;*/
void reverseTwoSubArray(SqList * array, int formerLength, int latterLength) {if ((formerLength + latterLength) != array->length) {printf("请输入合法的子数组长度~\n");exit(0);}reverse(array, 0, formerLength - 1);                                  //先转置前m个元素reverse(array, formerLength, formerLength + latterLength - 1);        //后转置后n个元素reverse(array, 0, formerLength + latterLength - 1);                   //最后转置整个数组
}

        3.算法的时间和空间复杂度 : 

        (1) 时间复杂度 : 

        Let's break down the operations in the reverseTwoSubArray function:

        The first reverse call operates on the first subarray of length formerLength.
        The second reverse call operates on the second subarray of length latterLength.
        The third reverse call operates on the entire array of length n (where n = formerLength + latterLength).
        Let's look at the reverse function:

        It performs swaps for half the length of the subarray it's operating on.
        So, the total number of operations is:

        formerLength/2 (first reverse)
        latterLength/2 (second reverse)
        n/2 (third reverse, where n = formerLength + latterLength)
        Adding these up: formerLength/2 + latterLength/2 + n/2 = n/2 + n/2 = n

        Therefore, the total number of operations is proportional to n, giving us O(n) time complexity.

        (2) 空间复杂度 : 

        The space complexity is O(1) (constant space) because:

        We're not using any additional data structures that grow with the input size.
        We're performing the reversal in-place, meaning we're only using a fixed amount of extra space regardless of the input size.
        The only extra space used is for a few variables (like temp in the reverse function), which doesn't change regardless of the array size.
        Even if the input array is very large, we don't need any more memory than these few variables. This is why we say the space complexity is constant, or O(1).


七、数组元素的循环移动 [2010真题]

        0.题目 : 

        设将n(n>1)个整数存放到一维数组R中,设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据由(X0,X1,.Xn-1)变换为(Xp,Xp+1,...,Xn-1,X0,X1,...Xp-1)。要求:

        1)给出算法的基本设计思想。

        2)根据设计思想,采用C语言描述算法,关键之处给出注释。

        3)说明你所设计算法的时间复杂度和空间复杂度。

        1.算法设计思想 :

        本质和上一题“数组中两个子数组的位置互换”一样,我们可以将一维数组R在逻辑上分为两个子数组,第一个数组就是循环左移的那p个元素构成的数组,即X0~Xp-1;第二个数组就剩剩余的那n-p个元素构成的数组。所以这道题目可以转化为——在一维数组R中包含两个顺序表,把含有p个元素和n-p个元素的两个顺序表互换位置

        所以,算法的设计思想——先将前p个元素逆置,再将后面n-p个元素逆置,最后将整个数组进行一次倒置,就可以得到我们最终想要的数组。即,先将{X0,X1,...,Xp-1,Xp,Xp+1,...Xn-1}变成{Xp-1,...X1,X0,Xn-1,...,Xp+1,Xp},然后再将它整体逆置,变成{Xp,Xp+1,...Xn-1,X0,X1,...,Xp-1},达到的最终效果就是整个一维数组R循环左移了p个位置。

        2.C语言描述 : 

                完整代码如下:(注意看注释)  

# include <stdio.h>
# include <stdlib.h># define MAX_SIZE 100//定义数据结构
typedef struct SqList {int data[MAX_SIZE];int length;int capacity;
} SqList;//函数声明
void initialize(SqList * array);
void reverse(SqList * array, int start, int end);
void loopMoveLeft(SqList * array, int p);int main(void) {SqList R;initialize(&R);//给出一个具体的顺序表,用于测试该算法。int array_R[] = {11, 13, 15, 12, 11, 11, 1, 2, 3, 4, 5};for (int i = 0; i < 11; ++i) R.data[i] = array_R[i];R.length = 11;printf("循环左移前的数组长这样儿——\n");for (int i = 0; i < R.length; ++i) printf("%d ", R.data[i]);loopMoveLeft(&R, 6);    //假设循环左移6个元素printf("\n循环左移后的数组长这样儿——\n");for (int i = 0; i < R.length; ++i) printf("%d ", R.data[i]);return 0;
}/**function : initialize(as its name)parameter list : (1) array : the operated array*/
void initialize(SqList * array) {array->length = 0;array->capacity = MAX_SIZE;
}/**function : reverse(just a certain part of an array)parameter list : (1)array---operated arraylist;(2)start---the index of the opening element of the subarray;(3)end---the index of the ending element of the subarray;*/
void reverse(SqList * array, int startIndex, int endIndex) {int temp = 0;int subArrayLength = endIndex - startIndex;for (int i = 0; i < subArrayLength / 2; ++i) {temp = array->data[startIndex];array->data[startIndex] = array->data[endIndex - i];array->data[endIndex - i] = temp;startIndex++;}
}/**function : loop move left p elements of an arraylistparameter list : (1) array---which array you want to cope with(2) p---the number of elements which will be loop move left
*/
void loopMoveLeft(SqList * array, int p) {if (array == NULL) {printf("请传入合法的数组~\n");exit(0);}if (array->length == 0) {printf("数组为空~\n");exit(0);}   // Handle cases where p is larger than array lengthp = p % array->length;if (p == 0) return;  // No movement neededreverse(array, 0, p-1);                           //先逆置前p个元素reverse(array, p, array->length - 1);             //再逆置后n-p个元素reverse(array, 0, array->length - 1);             //最后逆置整个数组
}

                运行结果 : 

        3.算法的时间和空间复杂度 : 

        (1) 时间复杂度

        p/2 + (n-p)/2 + n/2 = n,所以时间复杂度为O(n)。(更详细地说明见上一题)

        (2) 空间复杂度

        只使用了几个辅助变量,所以空间复杂度为O(1)。(更详细地说明见上一题)


Δ总结

  • up会根据数组--->链表--->二叉树--->图,这么一个顺序来分享408算法题的解题思路和方法。
  • 这篇博文写得不长,一共也就七道题,而且这七道题难度都不高,但是以“数组”作为算法题的入门再合适不过了;况且这七道题目之间也有紧密的联系,比方说第二题“数组元素的倒置”就是第六题和第七题的基础,而第七题又借鉴了第六题的思路。
  • 🆗,以上就是这篇博文的全部内容了,感谢阅读!

        System.out.println("END--------------------------------------------------");

相关文章:

C 408—《数据结构》算法题基础篇—数组(通俗易懂)

目录 Δ前言 一、数组的合并 0.题目&#xff1a; 1.算法设计思想&#xff1a; 2.C语言描述&#xff1a; 3.算法的时间和空间复杂度 : 二、数组元素的倒置 0.题目 : 1.算法设计思想 : 2.C语言描述 : 3.算法的时间和空间复杂度 : 三、数组中特定值元素的删除 0.题目 : …...

AI秘境-墨小黑奇遇记 - 初体验(一)

“怎么可能&#xff01;”墨小黑盯着屏幕上的代码&#xff0c;整个人都不好了。调试了三遍&#xff0c;翻了几遍书&#xff0c;结果还是不对。就像你以为自己早起赶车&#xff0c;结果发现闹钟根本没响一样崩溃。 这是他第一次真正接触人工智能实战任务——实现一个简单的感知…...

文件IO813

标准IO文件定位&#xff1a; fseek函数&#xff1a; 功能&#xff1a;将stream流文件中的文件指针从whence位置开始偏移offset个字节的长度。 int fseek(FILE *stream , long offset, int whence); FILE *stream 指的是所需要定位的文件&#xff08;文化定位前提是文件要被打…...

STP(生成树)的概述和工作原理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…...

从AGV到立库,物流自动化的更迭与未来

AGV叉车 随着柔性制造系统的广泛应用&#xff0c;小批量、多批次的生产需求不断增强&#xff0c;“订单导向”生产已经成为趋势。这也让越来越多的企业认识到&#xff0c;产线的智能设备导入只是第一步&#xff0c;要想达到生产效率的最优解&#xff0c;物流系统的再优化必须提…...

阴阳脚数码管

1.小故事 最近&#xff0c;我接到了一个既“清肺”又“烧脑”的新任务&#xff0c;设计一个低功耗蓝牙肺活量计。在这个项目中我们借鉴了一款蓝牙跳绳的硬件设计方案&#xff0c;特别是它的显示方案——数码管。 在电子工程领域&#xff0c;初学者往往从操作LED开始&#xff…...

【Vue3-Typescript】<script setup lang=“ts“> 使用 ref标签 怎么获取 refs子组件呢

注意&#xff1a;请确保子组件已经正确挂载&#xff0c;并且通过 defineExpose 暴露了您想要在父组件中访问的属性或方法 parent.vue <template><child ref"childRef"></child><button click"fun">点击父组件</button> &l…...

npm 超详细使用教程

文章目录 一、简介二、npm安装三、npm 的使用3.1 npm初始化项目3.2 安装包3.3 安装不同版本包3.4 避免系统权限3.5 更新包3.6 卸载包3.7 执行脚本3.8 pre- 和 post- 脚本3.9 npm link3.10 发布和卸载发布的包3.11 使用npm版本控制3.22 npm资源 四、总结 一、简介 npm&#xff…...

TypeScript函数

函数 函数:复用代码块 函数可以不写返回值 调用函数-----函数名() function a(){console.log(无参函数); } a();需要再函数后&#xff0c;写上返回值类型 没有返回值 使用void function e():string{return 可乐 } console.log(我得到了e()); function d():void{console.l…...

中海油某海上平台轨道巡检机器人解决方案

配电房作为能源传输和分配的核心枢纽&#xff0c;其安全运行直接影响到企业的生产稳定性和安全性。对于中海油这样的大型能源企业&#xff0c;配电房的运行状况至关重要。然而&#xff0c;传统的人工巡检方式存在效率低、作业风险高、巡检误差大等问题。为提升巡检效率、降低安…...

【NXP-MCXA153】SPI驱动移植

介绍 SPI总线由摩托罗拉公司开发&#xff0c;是一种全双工同步串行总线&#xff0c;由四个IO口组成&#xff1a;CS、SCLK、MISO、MOSI&#xff1b;通常用于CPU和外设之间进行通信&#xff0c;常见的SPI总线设备有&#xff1a;TFT LCD、QSPI FLASH、时钟模块、IMU等&#xff1b…...

Python if 编程题|Python一对一辅导教学

你好&#xff0c;我是悦创。 以下为 if 编程练习题&#xff1a; 1. 奇数乘积问题 题目描述: 编写一个程序&#xff0c;判断给定的两个整数是否都是奇数&#xff0c;如果是&#xff0c;返回它们的乘积&#xff1b;如果不是&#xff0c;返回它们的和。输入: num1, num2输出: n…...

机器学习——第十一章 特征选择与稀疏学习

11.1 子集搜索与评价 对一个学习任务来说&#xff0c;给定属性集&#xff0c;其中有些属性可能很关键、很有用&#xff0c;另一些属性则可能没什么用.我们将属性称为"特征" (feature) &#xff0c;对当前学习任务有用的属性称为"相关特征" (relevant featu…...

花式表演无人机技术详解

花式表演无人机作为现代科技与艺术融合的典范&#xff0c;以其独特的飞行姿态、绚烂的灯光效果及精准的控制能力&#xff0c;在各类庆典、体育赛事、音乐会等合中展现出非凡的魅力。本文将从以下几个方面对花式表演无人机技术进行详细解析。 1. 三维建模与编程 在花式表演无人…...

服务器那点事--防火墙

Linux服务器那点事--防火墙 Ⅰ、开启关闭Ⅱ、放开端口 Ⅰ、开启关闭 禁止防火墙开机自启systemctl disable firewalld 关闭防火墙systemctl stop firewalld 查看防火墙状态systemctl status firewalldⅡ、放开端口 例如&#xff1a;放开3306端口 设置放开3306端口 [rootbpm2…...

C:每日一题:单身狗

​​​​ 一、题目&#xff1a; 在一个整型数组中&#xff0c;只有一个数字出现一次&#xff0c;其他数组都是成对出现的&#xff0c;请找出那个只出现一次的数字。 整型数组 int arr[ ] {1,1,2,2,3,4,4} 二、思路分析&#xff1a; 1.&#xff0c;明确目标&#xff0c;选择…...

SQL之使用存储过程循环插入数据

1、已经创建了任务日志表 CREATE TABLE t_task_log (id bigint NOT NULL AUTO_INCREMENT,task_id bigint NOT NULL COMMENT 任务ID,read_time bigint NOT NULL COMMENT 单位秒&#xff0c;读取耗时,write_time bigint NOT NULL COMMENT 单位秒&#xff0c;写入耗时,read_size …...

智慧楼宇公厕系统小程序,提高卫生间管理使用效率

在当今的智慧楼宇中&#xff0c;公厕系统的管理和使用效率成为了衡量楼宇品质的重要指标之一。智慧楼宇公厕系统小程序的出现&#xff0c;为解决这一问题带来了全新的思路和方法。 一、检查公厕环境数据 智慧公厕系统不仅关注如厕的基本需求&#xff0c;还注重提升如厕环境的质…...

深度剖析:云数据库与传统数据库的显著差异

【若您对以下内容感兴趣&#xff0c;欢迎关注或联系我们】 在当今数字化时代&#xff0c;数据库技术不断演进&#xff0c;云数据库和传统数据库作为两种主要的数据库类型&#xff0c;在多个方面存在明显区别。下面我们将深入探讨这些差异。 一、部署方式 云数据库&#xff1…...

# 利刃出鞘_Tomcat 核心原理解析(六)

利刃出鞘_Tomcat 核心原理解析&#xff08;六&#xff09; 一、Tomcat专题 - 内容 1、Web 应用配置 2、Tomcat 管理配置 3、JVM 配置 4、Tomcat 集群 5、Tomcat 安全 6、Tomcat 性能调优 7、Tomcat 附加功能。 二、Tomcat专题 - Web应用配置介绍 1、Web.xml 配置文件…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...