零基础入门C语言之C语言实现数据结构之顺序表经典算法
在阅读本篇文章之前,建议读者优先阅读专栏内前面的文章。
目录
前言
一、经典算法OJ题:移除元素
二、经典算法OJ题:合并两个有序数组
三、关于顺序表的问题和思考
总结
前言
本篇文章借由力扣中的两道经典题目来介绍顺序表中的经典算法。
一、经典算法OJ题:移除元素
我给出这道题的测试链接:
27. 移除元素 - 力扣(LeetCode)
题目描述如下:


其实这道题的思路很简单,我们可以直接创建一个新数组,然后遍历原数组,如果原数组中的数据和我们要求的数据不相等,那就把它移动到新数组中;否则跳过即可。但是很遗憾,题目中已经明确给出了要求,不允许创建新的数组空间,那我们就只能在原数组上进行操作了。
那么在这里我们就可以使用双指针法,也就是创建两个变量src和dst,如果src指向值为val,那就让它自增;否则就让nums[dst] = nums[src],然后二者分别自增即可。这样最后只要返回dst即可。
请读者思考如何实现这段代码,我给出我的示例:
int removeElement(int* nums, int numsSize, int val) {int src = 0;int dst = 0;for(int i = 0; i < numsSize; i++){if(nums[src] == val){src++;}else{nums[dst] = nums[src];src++;dst++;}}return dst;
}
二、经典算法OJ题:合并两个有序数组
这道题的链接如下:
88. 合并两个有序数组 - 力扣(LeetCode)
题目描述如下:

同样,这道题的思路也很简单,我们完全可以给两个数组一人一个指针,然后比对二者指向的值的大小,然后按照顺序将其填充到融合的新数组中。但是同样遗憾的是,题目中明确指出让我们将数据都存储在nums1之中,那么此时我们该如何操作呢?
显然我们可以不管三七二十一,直接把nums2数组中的数据全部填充到nums1数组之中,然后使用我们前面讲过的排序算法进行排序,但是由于我们之前讲过的冒泡排序属于效率较为低下的算法,它无可避免的会影响到我们代码整体的运行速度。
此时我们其实可以借鉴一下我们刚开始的思路,我们不必让两个指针都指向最前面的元素,恰恰相反,我们可以让其指向数组的最后一个元素,然后让二者比大小,谁更大就被放在最后面,这样最后一定可以完成。那么这段代码应该如何实现呢?我给出一段示例代码:
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {int i = m - 1; int j = n - 1; int k = m + n - 1; while (j >= 0) {if (i >= 0 && nums1[i] > nums2[j]) {nums1[k--] = nums1[i--];} else {nums1[k--] = nums2[j--];}}
}
三、关于顺序表的问题和思考
首先,在涉及到顺序表中间以及头部的插入删除时,时间复杂度为O(n),关于这个时间复杂度我们之后会进行详细说明。其次,在增容时我们需要申请新空间,拷贝数据,释放旧空间,这对于我们的性能有着不小的消耗。最后,我们在增容的时候一般是二倍增长,这就导致了一定程度上的空间浪费。
那么我们该如何解决上述问题呢?很简单,我们需要一种新的数据结构,也就是链表,那么关于链表究竟是什么?我们且听下回分解!
总结
本文通过两道力扣算法题介绍了顺序表的经典处理技巧。第一题"移除元素"采用双指针法直接在原数组操作,第二题"合并有序数组"通过逆向双指针实现高效合并。文章还分析了顺序表在插入删除、空间扩容等方面存在的性能问题,并指出链表结构将是解决这些问题的方向。这两道题目展示了顺序表的基本操作思路,为后续学习更复杂的数据结构奠定了基础。
