上期给各位宝子们分享了分治策略和二分查找,最后给大家留了一个问题就是:有序循环数组的二分查找。我们上硬货
目录
有序循环数组的二分查找
有这样一个从小到大有序的数组,现在我们改变条件:让他部分有序
在这样的一个数组当中我们找出最小的元素的位置,使用二分查找。
同理最大的也是这个思路
思路:
首先我们先来判断左指针和右指针指向的元素大小,如果左小于右说明我们这个数列是完全有序,返回arr[left]即left指针指向的这个元素就是我们要找的最小元素
左大于右:(我们找到中间元素,利用中间元素与左指针和右指针的大小来进行查找)
由上图可知,5>4所以我们找到中间指针:9
1.我们来判断中间指针和左右两个指针,9>5,因为部分有序所以5到9这个范围我们就不找了,最小元素肯定不在这个里面,所以我们的左指针指向mid+1的位置
2.left指向10,right指向4,mid指向2
3.因为中间指针数据比右指针的数据小,所以从中间指针到右指针这个范围我们就不用找了,我们继续将规模缩小,right指针指向mid-1
此时:左指针和中间指针相等,这就找到我们最大的元素了,所以我们left继续向右偏移,这个时候我们就找到我们最小元素所在位置了
代码实现
int funa(int* ar, int left, int right) {
if (ar[left] < ar[right]) {
return left;
}
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (ar[mid] >= ar[left]) {
left = mid + 1;
}
else if (ar[mid] < ar[right])
{
right = mid - 1;
}
if (ar[left] < ar[right]) {
return left;
}
}
}
int main() {
int ar[9] = { 5,6,7,8,9,1,2,3,4 };
int i = funa(ar, 0, 8);
printf("最小的数在第%d位置", i);
}
注意:
1.条件:left<=right:如果去掉等号只适合数组总元素个数是奇数的,而偶数就会报错,原因就是我们偶数的时候left指针和right指针和mid指针在一个数据上,而奇数的时候我们left指针和right指针差一个
好了接下来进入正题--->排列树
排列树
问题描述:数组{1,2,3}可以排列成{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}这几种结果,我们现在利用分治思想来实现
思路
首先:我们先确定第一个元素:1,2,3三种情况
其次:确定完首元素后,第二个元素(我们以首元素为1为例):2,3情况
最后:确定完前两个元素,第三个元素:就剩下2异或3,一种情况
这样我们通过层层削减问题规模来达到全排列
代码实现
#include<stdio.h>
#include<iostream>
void Perm(int* nums, int k, int m) {
if (k == m) {
for (int i = 0; i <= m; i++) {
printf("%5d", nums[i]);
}
printf("\n");
}
else {
for (int i = k; i <=m; i++) {
std::swap(nums[i],nums[k]);
Perm(nums, k + 1, m);
std::swap(nums[i], nums[k]);
}
}
}
int main() {
int nums[] = { 1,2,3 };
int lenth = sizeof(nums) / sizeof(nums[0]);
Perm(nums, 0, 2);
}
分析:
如图所示,在这个数组中我们定义两个变量:一个指向第一个元素,一个指向最后一个元素,当第一个元素和最后一个元素相等(即k==m)说明我们数组只有一个元素,这个时候我们打印即可,无需排列
当k!=m时,我们先进行首元素排列
这次递归完打印{1,2,3}
swap函数主要的作用就是某个位置上的元素的选择,如第一位置可以是1,2,3,我们通过交换函数将2移动到第一个位置,这个时候就能实现首元素是2的要求,但是交换完我们必须再交换一次。
通过i的变化让我们确定接下来元素,如确定完第一个位置是1,{2,3},{3,2}两种可能这个时候就需要i这个变量来控制接下来元素的确定
子集树
我们都学过集合,小白来考考大家,{1,2,3}这个集合子集是?
答案是:{1,2,3},{1,2},{1,3},{2,3},{1},{2},{3},{空集}
分析
我们先来看这棵树,类比哈夫曼树编码特点,让左子树为1右子树为0,1为存在,0为不存在,通过这棵树我们可以得到子集
代码实现
void func(int* arr, int* brr, int i,int n) {
if (i == n) {
for (int j = 0; j < n; j++) {
if (brr[j] == 1) {
printf("%5d", arr[j]);
}
}
printf("\n");
}
else {
brr[i] = 1;
func(arr, brr, i + 1, n);
brr[i] = 0;
func(arr, brr, i + 1, n);
}
}
int main() {
int arr[] = { 1,2,3 };
int brr[3] = { 0 };
func(arr, brr, 0, 3);
}
以上就是今天的所有内容啦,希望各位宝子能够喜欢
小白会继续努力的。