Day 7_2 two pointers


编写的内容都是很简略的,适合在学过的情况下快速回忆这些算法,没有学过的话,具体了解可以百度

1.two Pointers

例子:给定一个递增的正整数序列和一个M,求序列中的两个不同位置的数a和b,使得他们的和恰好等于M,输出所有满足条件的方案
解决方案

  1. 使用二重循环枚举,但是如果序列很长时间复杂度过高
void foreach(int a[],int M){
	int n = sizeof(a)/sizeof(int); 
	for(int i=0;i<n;i++){
		for(int j=i+1;j<n;j++){
			if(a[i]+a[j] == M)
				printf("%d %d\n",a[i],a[j]); 
		}
	}
}
  1. 优化上述方案一
    因为序列是递增的,找到a[i]+a[j] = M,从i,j+1往后还有i+1,j往后,剩下的两个数相加肯定大于M,没必要继续往下遍历
    初始令i= 0,j = n-1,i逐渐往右移,j往左移
    1)若a[i]+a[j] = M,a[i+1]+a[j] > M,a[i]+a[j-1] < M,但是a[i+1]+a[j-1] 与 M关系未知,所以答案只可能在[i+1,j-1]区间产生,令i = i +1,j = j-1继续
    2)若a[i]+a[j] > M,a[i+1]+a[j] > M,但是a[i]+a[j-1] 与 M关系未知,所以答案只可能在[i,j-1]区间产生,令j = j-1继续
    3)若a[i]+a[j] < M,a[i]+a[j-1] < M,但是a[i+1]+a[j] 与 M关系未知,所以答案只可能在[i+1,j]区间产生,令i = i + 1继续
    反复执行上述三个步骤,知道i>=j成立
void foreach2(int a[],int M){
	int n = sizeof(a)/sizeof(int); 
	int i=0,j = n-1;
	while(i<j){
		if(a[i]+a[j] == M){
			printf("%d %d\n",a[i],a[j]);
			i++;
			j--;
		}else if(a[i]+a[j] < M){
			i++;
		}else{
			j--;
		}		 
	}
}

2.归并排序

2-路归并排序:序列中的数两两分组,分成n/2个组,组内单独排序,然后两个组两个组进行合并,得到n/4个组,组内单独排序,以此类推。直到只剩下一个组

合并函数

const int maxn = 100; 
//将数组A的[L1,R1]与[L2,R2]的区间合并为有序区间 
void merge(int A[],int L1,int R1,int L2,int R2){
	int i = L1,j = L2;
	int temp[maxn],index = 0;
	while(i <= R1 && j<= R2){
		if(A[i]<=A[j]){
			temp[index++] = A[i++];
		}else{
			temp[index++] = A[j++];
		}
	} 
	while(i <= R1)	temp[index++] = A[i++];
	while(j <= R2)	temp[index++] = A[j++];
	for(int i = 0;i<index;i++){
		A[L1 + i] = temp[i];
	}
}

1.递归实现

//将array数组当前区间[left,right]进行归并排序 
void mergeSort(int A[],int left,int right){
	if(left < right){
		int mid = (left+right)/2;
		mergeSort(A,left,mid);
		mergeSort(A,mid+1,right);
		merge(A,left,mid,mid+1,right);
	}
}

2.非递归实现
每次分组内元素个数都是2 的倍数,于是设定一个step步长,初值为2,然后将数组的每step个元素作为一组,将其内部排序,step乘2,继续之前步骤,直到 step/2 超过元素个数n

void mergeSort(int A[],int left,int right){
	//step为组内元素个数,step/2 为左区间元素个数,等号可以不取 
	for(int step = 2;step/2<=n;step *=2){
		//每step个元素一组,组内前step/2个元素进行合并 
		for(int i = 1;i<=n;i+=step){	//对每一组 
			int mid = i + step/2 - 1;	//左子区间元素个数为step/2 
			if(mid + 1 <= n){			//右子区间存在元素则合并 
				merge(A,i,mid,mid+1,min(i + step - 1,n));
			}  
		}
	} 
}

3.快速排序

待排序数组A,在A中找一哨兵(尽量随机确定哨兵),例如A[1],调整数组序列,使得A[1]的左边的数都小于A[1],右边的都大于A[1],然后A[1]左边和右边的序列各自又找一哨兵,重复执行

  1. 先将A[1]存到临时变量temp里面,并令两个下标left = 1,right = n,指向序列首尾
  2. 只要A[left]<temp,则left不断自增右移,当某个时候A[left]>=temp,将元素A[left]挪到right指向的元素A[right]处
  3. 只要A[right]>temp,则right不断自增左移,当某个时候A[lright]>=temp,将元素A[right]挪到left指向的元素A[left]处
  4. 重复2,3,知道left与right相遇,把temp放到相遇的地方
#include<stdio.h>
int Partition(int A[],int left,int right){
	int temp = A[left];
	while(left < right){
		while(left < right && A[right] > temp)	right--;
		A[left] = A[right];
		while(left < right && A[left] <= temp)	left++;
		A[right] = A[left];
	}
	A[left] = temp;
	return left;
} 
//快速排序,left,right是序列首尾的下标
void quickSort(int A[],int left,int right){
	if(left < right){
		int pos = Partition(A,left,right);
		quickSort(A,left,pos-1);
		quickSort(A,pos+1,right);
	} 
} 
int main(){
	int a[] = {1,5,4,8,3,6,7,9,10,25,41,62,26,35};
	quickSort(a,0,13);
	for(int i = 0;i<14;i++)
		printf("%d ",a[i]);
	return 0;
}

序列比较随机时,效率最高,序列接近有序时,会达到最坏复杂度,因此选定哨兵随机选择

1)生成随机数的方法

注意添加的两个头文件,还有初始化随机种子

#include<stdio.h>
#include<stdlib.h>
#include <time.h> 
int main(){
	srand((unsigned)time(NULL)); //初始化随机种子 
	for(int i = 0;i<10;i++)
		printf("%d ",rand());	 //生成[0,32767]之间的数,常数RAND_MAX = 32767  
	printf("\n\n");
	//rand()%a	生成[0,a-1]之间的数
	//rand()%(b-a+1) + a	生成[a,b]之间的数
	for(int i = 0;i<10;i++)
		printf("%d ",rand()%2);		//[0,1] 
	printf("\n\n");
	for(int i = 0;i<10;i++)
		printf("%d ",rand()%5+3);	//[3,7]
	printf("\n\n");

	//生成大于32767的数 ,1.0*rand()/RAND_MAX随机生成一比例 
	for(int i = 0;i<10;i++)
		printf("%d ",(int)(round(1.0*rand()/RAND_MAX*50000+10000)));//[10000,60000]
	return 0;
}

随机快排

扫描二维码关注公众号,回复: 8731868 查看本文章
#include<stdio.h>
#include<stdlib.h>
#include <time.h> 
#include <math.h> 
int randPartition(int A[],int left,int right){
	int p = round(1.0*rand()/RAND_MAX*(right-left)+left);
	int t = A[p];
	A[p] = A[left];
	A[left] = t;
	int temp = A[left];
	while(left < right){
		while(left < right && A[right] > temp)	right--;
		A[left] = A[right];
		while(left < right && A[left] <= temp)	left++;
		A[right] = A[left];
	}
	A[left] = temp;
	return left;
} 
//快速排序,left,right是序列首尾的下标
void quickSort(int A[],int left,int right){
	if(left < right){
		int pos = randPartition(A,left,right);
		quickSort(A,left,pos-1);
		quickSort(A,pos+1,right);
	} 
} 
int main(){
	srand((unsigned)time(NULL));
	int a[] = {1,5,4,8,3,6,7,9,10,25,41,62,26,35};
	quickSort(a,0,13);
	for(int i = 0;i<14;i++)
		printf("%d ",a[i]);
	return 0;
}
发布了26 篇原创文章 · 获赞 3 · 访问量 203

猜你喜欢

转载自blog.csdn.net/qq_41898248/article/details/103794950
今日推荐