1.全排列:
template<class Type>
void Swap(Type &a,Type &b)
{
Type c = a;
a = b;
b = c;
}
void Perm2(int arr[], int start, int end)
{
if(NULL == arr)
{
return;
}
if(start == end)//走到最后以为 进行打印
{
for(int i=0; i<=end; i++)
{
cout << arr[i] <<" ";
}
cout << endl;
}
else
{
for(int i=start; i<=end; i++) //以第i个为基准不要动 交换其他的进行全排列
{
swap(arr[i], arr[start]);//全排列调用两次交换函数一次递归 而全部子集调用01赋值后调用两次递归
Perm2(arr, start+1, end);//这里不能传i的原因是:i代表基准值的下标与第一个数进行交换,然后剩下两个全排列打印,数组长度才012,这里如果传i,那么递归调用就传2+1了,越界了
swap(arr[i], arr[start]);//交换玩之后,重新交换回来,让i重新指定基准值 与第一个值进行交换 //这里应该传start,让其指向最后一个数的下标时就打印
} //递归不能传i的原因 就是当i==end的时候 递归i+1会越界
}
}
int main()
{
int ar[]={1,2,3};
int n = sizeof(ar)/sizeof(ar[0]);
Perm2(ar,0,n-1);
return 0;
}
2.全部子集
void fun2(int arr[], int brr[], int i, int n)
{
if(NULL == arr || NULL == brr)
{
return;
}
if(i == n)//走到最后以为 进行打印
{
for(int j=0; j<n; j++)
{
if(brr[j] == 1)
{
cout << arr[j] << " ";
}
}
cout << endl;
}
else
{
brr[i] = 1;
fun2(arr, brr, i+1, n);//全排列调用两次交换函数一次递归 而全部子集调用01赋值后调用两次递归
brr[i] = 0;
fun2(arr, brr, i+1, n);
}
}
int main()
{
int ar[]={1,2,3};
int br[]={0,0,0};
int len = sizeof(ar)/sizeof(ar[0]);
fun2(ar,br,0,len);
return 0;
}
3.在一个数组中找第K小的数
思路:
①:数组长度用一个变量标记不方便,那么将这个数组用两端指向起来,再从中找第k小的数值
分化:我们将大问题转化为规模小的小问题
②:用快速排序找到基准值,查看基准值左边有多少数字,如果这个数字大于我们k,那么我们要找的数肯定在这个基准值的左半侧,因为左半侧的值都小于或等于基准值,那么我们将问题就转化为从左半边这个小规模里找第k小的数
③:如果这个数组小于k,则我们要找的数肯定在这个基准值的右半侧,因为右半侧的值都大于基准值,那么我们将问题就转化为从左半边这个小规模里找第(k-pos)小的数,pos为左半侧的数的个数,比如我们要找第8小的数,但是左边只有6个数,那么我们只用在右半边找第二小的数即可。
template<class TYPE>
int Partition2(TYPE arr[], int left, int right)//基础快排算法
{
TYPE tmp = arr[left];
int i = left;
int j = right;
while(i < j)
{
while(i < j && arr[j]>tmp)
{
--j;
}
if(i < j) {arr[i] = arr[j];}
while(i < j && arr[i] <= tmp)
{
++i;
}
if(i < j){arr[j] = arr[i];}
}
arr[i] = tmp;
return i;
}
template<class TYPE>
int SelectK2(TYPE arr[], int left, int right, int k)
{
if(left == right && k==1)//如果范围里只有一个数,且要找的也是第1小 则返回return arr[left]
{
return arr[left];
}
int index = Partition2(arr, left, right);//获取基准值
int pos = index - left + 1;//获取划分后,基准值左半侧的数值的个数pos
if(k <= pos) //如果小于等于k,则在左半侧找第k小
{
return SelectK2(arr, left, index, k);
}
else //如果大于k,则在右半侧找第(k-pos)小
{
return SelectK2(arr, index+1, right, k-pos);
}
}
template<class TYPE>
int SelectK_Min2(TYPE arr[], int len, int k)
{
assert(NULL != arr && len > 1);
return SelectK2(arr, 0, len-1, k);//将数组范围用两个变量指向起来,便于操作
}
int main()
{
int ar[]={56,12,34,78,90,67,45,100,89,18};
int n = sizeof(ar)/sizeof(ar[0]);
for(int k = 1;k<=n;++k)
{
cout<<k<<" => "<<SelectK_Min2(ar,n,k)<<endl;
}
return 0;
}
我们为了防止快排有序,以便于加快效率,则进行优化,将每次的基准值与随机值挂钩
template<class Type>
int RandPartition(Type *ar,int left,int right)
{
srand(time(NULL));
int pos = (rand() % (right - left + 1 )) + left;
swap(ar[pos],ar[left]);
return Partition(ar,left,right);
}