在这篇文章中,我们解释了使用Hoare's Partition和Lomuto Partition将偶数移到数组前面的两种有效方法。
内容表:
- 问题陈述
- 方法1:使用Hoare分割法
- 方法2:使用Lomuto分割法
让我们来了解并解决这个问题。
问题陈述
给定一个正数的数组,以这样的方式划分数组,使所有的偶数都在数组的前面。
例子
Input : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Output: {2, 4, 6, 8, 10, 1, 3, 5, 7, 9}
注意:偶数和奇数的相对顺序并不重要
Another Solution:
{2, 6, 4, 10, 8, 1, 3, 7, 9, 5}
Following Outputs are wrong.
{1, 3, 5, 7, 9, 2, 4, 6, 8, 10}
{2, 1, 4, 3, 6, 5, 8, 7, 10, 9}
这个问题类似于隔离0和1,可以用荷兰国旗算法的变化来解决。
各种分区方案
这个问题可以用一个分区方案来解决,比如:
- 霍尔分割法
- Lomuto分区
方法1:使用Hoare分区法
它是基于双指针法,指针start和end被初始化为数组的两端,并相互移动,直到发生倒置,奇数在左边,偶数在右边。在反转时进行交换操作,这个过程重复进行,直到起点小于终点。
算法/步骤
- 初始化i = low,j = high。
- 将i递增1,直到i处出现的元素是偶数。
- j减1,直到i处的元素是奇数。
- 将i处的元素与j处的元素交换。
- 重复步骤2-4,直到i小于j。
代码
def segregateEvenOdd(arr):
j = 0
i = len(arr) - 1
while i < j:
while i<len(arr) and arr[i]%2 == 0:
i = i + 1
while j>=0 and arr[j]%2 != 0:
j = j - 1
if i < j :
swap(arr[i],arr[j])
例子
输入:{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
进行的交换:0
1 2 3 4 5 6 7 8 9 10
| |
i j
已执行的互换:0 + 1 = 1
10 2 3 4 5 6 7 8 9 1
| |
i j
已执行的互换:1
10 2 3 4 5 6 7 8 9 1
| |
i j
已执行的互换:1
10 2 3 4 5 6 7 8 9 1
| |
i j
已执行的互换:1 + 1 = 2
10 2 8 4 5 6 7 3 9 1
| |
i j
已执行的互换:2
10 2 8 4 5 6 7 3 9 1
| |
i j
已执行的互换:2
10 2 8 4 5 6 7 3 9 1
| |
i j
执行的互换操作:2 + 1 = 3
10 2 8 4 6 5 7 3 9 1
| |
i j
END
比较操作的数量较多,但交换操作较少。因此,它是更有效的方法,但与Lomuto分区相比,很难理解。
时间复杂度:O(N),其中N是数组的长度
空间复杂度::O(1)
方法2:使用Lomuto分区
我们不从两端移动指针,而是从数组的低位置移动到高位置。当我们在数组中迭代时,我们用滑动目标索引交换偶数元素。滑动目标索引是一个分隔偶数和奇数元素的分区索引,最初它指向-1。
算法/步骤
- 初始化sliding_index = low - 1,因为最初没有偶数元素存在于左边的子阵列中,i = low。
- 检查i处存在的元素是偶数还是奇数。
- 如果是偶数,则将sliding_index增加1,并将sliding_index和i处的元素交换。
- 否则,不做任何操作。
- 将i增加1。
- 重复步骤2-5,直到i小于或等于高。
代码
def segregateEvenOdd(arr):
sliding_indx = -1
for i in range(0,len(arr)):
if arr[i]%2 == 0:
sliding_indx = sliding_indx + 1
swap(arr[i],arr[sliding_indx])
例子
输入:{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
让滑动的indx为i,迭代器为j
进行交换:0
1 2 3 4 5 6 7 8 9 10
| |
i j
已执行的互换:0
1 2 3 4 5 6 7 8 9 10
| |
i j
已执行的互换:0 + 1 = 1
2 1 3 4 5 6 7 8 9 10
| |
i j
已执行的互换:1
2 1 3 4 5 6 7 8 9 10
| |
i j
已执行的互换:1
2 1 3 4 5 6 7 8 9 10
| |
i j
已执行的互换:1 + 1 = 2
2 4 3 1 5 6 7 8 9 10
| |
i j
已执行的互换:2
2 4 3 1 5 6 7 8 9 10
| |
i j
已执行的互换:2
2 4 3 1 5 6 7 8 9 10
| |
i j
已执行的互换:2 + 1 = 3
2 4 6 1 5 3 7 8 9 10
| |
i j
已执行的互换:3
2 4 6 1 5 3 7 8 9 10
| |
i j
已执行的互换:3
2 4 6 1 5 3 7 8 9 10
| |
i j
已执行的互换:3 + 1 = 4
2 4 6 8 5 3 7 1 9 10
| |
i j
已执行的交换:4
2 4 6 8 5 3 7 1 9 10
| |
i j
已执行的交换:4
2 4 6 8 5 3 7 1 9 10
| |
i j
已执行的互换:4 + 1 = 5
2 4 6 8 10 3 7 1 9 5
| |
i j
END
Lomuto分区很容易实现和理解。但与Hoare分区相比,它的速度较慢,因为要进行更多的互换操作。
时间复杂度O(N),其中N是阵列的长度
空间复杂度::O(1)
通过OpenGenus的这篇文章,你一定对如何将偶数移到数组的前面有了完整的认识。