二、查找与排序(上)

递归

递归设计经验

  • 找重复(子问题)
  • 找重复中的变化量->参数
  • 找参数变化趋势->设计出口

练习策略

  • 循环改递归
  • 经典递归
  • 大量练习,总结规律,掌握套路
  • 找到感觉,挑战高难度

递归练习:
1.求n的阶乘

int f1(int n){
	if(n==1)
		return 1;
	return n*f1(n-1);	
}

2.打印i到j

void f2(int i,int j){
	if(i>j)
		return;
	cout<<i<<endl;
	f2(i+1,j);
}

3.对arr的所有元素求和

int f3(vector<int> arr,int begin){
	if(begin==arr.size()-1)
		return arr[begin];
	return arr[begin]+f3(arr,begin+1);
}

4.斐波那契数列

int fib(int n){
	if(n==1||n==2)
		return 1;
	return fib(n-1)+fib(n-2);
}

5.最大公约数

int gcd(int m,int n){
	if(n>m){
		int temp=n;
		n=m;
		m=temp;
	}
	if(n==0){
		return m;
	}
	return gcd(n,m%n);
} 

6.递归形式进行插入排序

void insertSort(vector<int> &arr,int k){
	if(k==0){
		return;
	}
	//对前k-1个元素排序 
	insertSort(arr,k-1);
	//把位置k的元素插入到前面的部分 
	int temp=arr[k];
	int index = k-1;
	while(index>-1&&temp<arr[index]){
		arr[index+1]=arr[index];
		index--;
	}
	arr[index+1]=temp;
} 

7.汉诺塔

//将1-N从A移动到B,C作为辅助
//		等价于:
//		1.1-(N-1)从A移动到C,B为辅助 
//		2.把N从A移动到B
//		3.1-(N-1)从C移动到B,A为辅助 
	 
void Hanio(int N,string from,string to,string help){
	if(N==1){
		cout<<"move "<<N<<" from "<<from<<" to "<<to<<endl;
		return;
	}
	Hanio(N-1,from,help,to);//先把N-1个盘子移动辅助空间上去
	cout<<"move "<<N<<" from "<<from<<" to "<<to<<endl;
	Hanio(N-1,help,to,from);//让N-1从辅助空间回到源空间上去 
} 

8.跨梯子

有N阶梯子,可以1步,2步,3步走,问有几种方式到达顶部。

//考虑到最后可以通过1步、2步、3步到达顶部,因此可以分解为f(n-1)、f(n-2)、f(n-3)种
#include<bits/stdc++.h>
using namespace std;
int f(int n)
{
	if(n==0)
		return 1;
	if(n==1)
		return 1;
	if(n==2)
		return 2; 
	return f(n-1)+f(n-2)+f(n-3);
}
int main()
{
	int n;
	cin>>n;
	cout<<f(n);
	return 0;
}

9.二分查找递归

#include<bits/stdc++.h>
using namespace std;
int binarySearch(int arr[],int low,int high,int key){
	if(low>high)
		return -1;
	int mid=(high+low)>>1;
	int midVal=arr[mid];
	if(midVal<key)
		return binarySearch(arr,mid+1,high,key);
	else if(midVal>key)
		return binarySearch(arr,low,high-1,key);
	else
		return mid;
} 
int main()
{
	int arr[100000];
	for(int i=0;i<100000;i++){
		arr[i]=i+1;
	}
	int target = 100000;
	cout<<binarySearch(arr,0,100000-1,target);
	return 0;
}

10.设计一个高效的求a的n次幂

#include<bits/stdc++.h>
using namespace std;
int mypow(int a,int n){
	if(n==0) return 1;
	int res=a;
	int ex = 1;
	//降低时间复杂度
	//通过乘2加快接近需要的幂次
	while((ex<<1)<=n){
		res *= res;
		ex<<=1;
	}
	return res*pow(a,n-ex);
} 
int main()
{
	int a=2;
	int n=15;
	cout<<mypow(a,n);
	return 0;
}

排序

  • 插入排序

从左往右遍历数组,将此时正在遍历的元素插入在其之前合适的位置,索引下标从1开始。

#include<bits/stdc++.h>
using namespace std;
void insertSort(vector<int> &vec){
	for(int i=1;i<vec.size();i++){
		int temp=vec[i];
		int j=i-1;
		while(j>-1&&temp<vec[j]){
			vec[j+1]=vec[j];
			j--;
		}
		vec[j+1]=temp;
		cout<<"第"<<i<<"轮"<<endl; 
		for(int k=0;k<vec.size();k++){
			cout<<vec[k]<<endl;
		}
	}
} 
int main()
{
	int arr[]={7,2,1,8,9,10,3,6,4,5};
	vector<int> vec(arr,arr+10);
	insertSort(vec);
	return 0;
}
  • 冒泡排序

外层从左往右遍历每个元素,内层从左往右遍历比较,将最大的数交换移动到最右,内层遍历长度随着i逐渐减小。

#include<bits/stdc++.h>
using namespace std;
void bubleSort(vector<int> &vec){
	for(int i=0;i<vec.size()-1;i++)
	{
		for(int j=0;j<vec.size()-i-1;j++){
			if(vec[j]>vec[j+1]){
				int temp=vec[j];
				vec[j]=vec[j+1];
				vec[j+1]=temp;
			}
		} 
	}
} 
int main()
{
	int arr[]={7,2,1,8,9,10,3,6,4,5};
	vector<int> vec(arr,arr+10);
	bubleSort(vec);
	for(int i=0;i<vec.size();i++){
		cout<<vec[i]<<endl;
	}
	return 0;
}
  • 希尔排序

即插入排序的缩小增量法,通过不断缩小增量提高效率。数组最开始无序时增量大,需要排序的元素个数少,排序快,之后逐渐有序,增量减小,因为已经大部分有序了,所以排序工作依然较快。

#include<bits/stdc++.h>
using namespace std;
void shellSort(vector<int> &vec){
	//不断地缩小增量 
	for(int interval = vec.size()/2;interval>0;interval=interval/2){
		for(int i=interval;i<vec.size();i++){
			int target = vec[i];
			int j=i-interval;
			while(j>-1&&target<vec[j]){
				vec[j+interval]=vec[j];
				j-=interval;
			}
			vec[j+interval]=target;
		}
	}
} 
int main()
{
    int arr[10]={6,1,7,4,10,10,9,3,0,5};
	vector<int> vec(arr,arr+10);
	shellSort(vec);
	for(int i=0;i<vec.size();i++){
		cout<<vec[i]<<endl;
	}
    
	return 0;
}

二分查找

int binarySearch(int arr[],int low,int high,int key){
	while(low<=high){
		int mid=(low+high)>>1;
		int midVal = arr[mid];
		if(midVal<key){
			low=mid+1;
		}
		else if(midVal>key){
			high=mid-1;
		}else{
			return mid;
		}
	}
	return -1;
}

二分查找变种应用:
1.翻转数组的最小值

将一个有序数组的前若干元素翻转拼接到数组最后形成新的数组,查找最小值的索引。如:{1,2,3,4,5},翻转前4个元素变成{5,1,2,3,4}

思路:
因为是有序,可以想到用效率更高的二分查找。
显而易见,最小值总是在最大值的后面,因此通过二分查找,最后的arr[end]即是最小值
注意:当中间值与arr[begin]、arr[end]都相同时,如{0,1,1,1,1}通过翻转变为{1,0,1,1,1}此时算出最小值为1,因此此时需要直接遍历查找出最小值

#include<bits/stdc++.h>
using namespace std;
int search(int arr[])
{
	int min=9999;
	for(int i=0;i<5;i++)
	{
		if(arr[i]<min)
			min=arr[i];
	}
	return min;
}
int reserveSearch(int arr[],int len)
{
	int begin=0;
	int end=len-1;
	//考虑特殊情况没有翻转
	if(arr[begin]<arr[end])
		return arr[begin];
	while(begin+1<end){
		int mid = (begin+end)>>1;
		//如果左值、右值、中值都相等则采用遍历查找
		if(arr[mid]==arr[begin]&&arr[mid]==arr[end])
			search(arr);
		if(arr[mid]>=arr[begin]){
			begin=mid;
		}else{
			end=mid;
		}
	}
	return arr[end];
}
int main()
{
	int arr[]={5,1,2,3,4};
	cout<<reserveSearch(arr,5);
	return 0;
}

2.在有空字符串中的有序字符串数组中查找

给出一个含有空字符串的有序字符串数组,查找指定元素的索引,查找元素不为空字符串。

#include<bits/stdc++.h>
using namespace std;
int indexOf(string arr[],string t,int len){
	int begin=0;
	int end=len-1;
	while(begin<=end){
		int indexOfMid=(begin+end)>>1;
		while(arr[indexOfMid]==""){
			indexOfMid++;
			if(indexOfMid>end)
				return -1;
		}
		if(arr[indexOfMid]<t){
			begin=indexOfMid+1;
		}else if(arr[indexOfMid]>t){
			end=indexOfMid-1;
		}else{
			return indexOfMid;
		}
	}
	return -1;
}
int main()
{
	string arr[]={"a","","ac","","ad","b","","ba"};
	int res=indexOf(arr,"b",8); 
	cout<<res<<endl;
	return 0;
}
发布了25 篇原创文章 · 获赞 0 · 访问量 1502

猜你喜欢

转载自blog.csdn.net/u014681799/article/details/86768257
今日推荐