数据结构三、顺序表的经典例题(一)

        前两篇我们介绍了如何用数组模拟实现一个静态顺序表,以及C++提供的容器vector。那么接下来,我给大家分享几道经典的顺序表算法题,来加深并学会运用顺序表。

一起来看下面这道题目:

这个问题也被称为荷兰国旗问题,其中蕴含的算法思想在后续的快速排序算法中也亦有体现。想要实现颜色的分类,那么我们可以对最终的数组分成三个部分,前一部分元素都是0,中间一部分元素都是1,后面一部分元素都是2,因此,我们需要定义三个指针。指针i:用来扫描整个数组;指针left:用来指向0区域的最后一个元素;指针right:用来指向2区域的第一个元素。 所以,原始数组的情况就被我们分成了这个样子:

   [0, left] [left + 1, i - 1] [i, right - 1] [right, n - 1]
//    0             1               待扫描           2

 我们现在来用{2, 0, 2,  1, 1, 0}这个数组来演试一下这个过程。首先,i是用来扫描整个数组,因此初始化为0。left表示0位置的最后一个元素,由于现在数组还没有分好块,我们可以让left初始化成-1。同理,让right初始化成n。

 现在i指向的是2这个元素,我们想让2这个元素进入到右边的区间(也就是[right, n-1]这个区间),该怎么做呢?我们可以先让i这个位置的值(这个位置的值为2的话)与right-1这个位置的值做交换,然后再让right--,这样就能把2这个元素囊括进右边的区间了。那么接下来有个小问题要注意,有人可能会想:交换完之后,让right--,再让i++去遍历下一个元素。NO!现在可不能直接i++去遍历下一个元素。因为我们交换完之后,确实让i这个位置的值(假设值为2)进入了我们分好的2区间内,但是同样的,我们把i-1这个位置的值也交换到了i这个位置处,可是我们还不知道i-1处的值是多少,还需要进行判断,因此,我们不能进行i++这个操作,这一点要注意!

     结合上面给的示例,第一步交换完之后,i这个位置处的值变成了0,我们想让0进入到第一个区间。类比上一个思想,让i位置处的值与left+1处的值做交换,再让left++,这样就把0囊括进了左边的区域。那么我们接下来要不要进行i++的操作呢?这里是需要的。为什么呢?因为[left + 1, i- 1]这段区间内的元素我们都是已经扫描完了的,所以直接进行i++的操作去扫描后面的元素就可以了。

当i扫描到1这个元素的时候,我们要让1进入到[left + 1, i - 1]这个区间,那么就很简单了,直接让i++就行。当i与right相遇的时候,整个数组也就被我们成功地分成了三块了。

因此,我们的思路可以用下面这张图来总结一下:

这里多说一点,在C++中,想要实现两个数的交换,我们不必再像C语言那样定义中间变量,然后在自己手写代码,而是可以直接调用C++为我们准备的库函数——swap。这个库函数的功能很强大,感兴趣的话可以自行上网了解,这里就不再做过多的解释了~ 

接下来我们来实现一下代码(这里我采用的是核心代码模式)

class Solution
{
public:
    void sortColors(vector<int>& nums)
    {
        int n = nums.size();
        int i = 0;
        int left = -1;
        int right = n;
        while (i < right)
        {
            if (nums[i] == 2)
            {
                swap (nums[i], nums[right - 1]);
                right--;
            }
            else if (nums[i] == 0)
            {
                swap (nums[i], nums[left + 1]);
                left++;
                i++;
            }
            else
                i++;
        }
    }
};

 那么关于本道题就讲解完毕了,学识有限,如有更好的解法,也欢迎大家在评论区讨论。我们下道题再见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值