编写的内容都是很简略的,适合在学过的情况下快速回忆这些算法,没有学过的话,具体了解可以百度
1.two Pointers
例子:给定一个递增的正整数序列和一个M,求序列中的两个不同位置的数a和b,使得他们的和恰好等于M,输出所有满足条件的方案
解决方案
- 使用二重循环枚举,但是如果序列很长时间复杂度过高
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]);
}
}
}
- 优化上述方案一
因为序列是递增的,找到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]左边和右边的序列各自又找一哨兵,重复执行
- 先将A[1]存到临时变量temp里面,并令两个下标left = 1,right = n,指向序列首尾
- 只要A[left]<temp,则left不断自增右移,当某个时候A[left]>=temp,将元素A[left]挪到right指向的元素A[right]处
- 只要A[right]>temp,则right不断自增左移,当某个时候A[lright]>=temp,将元素A[right]挪到left指向的元素A[left]处
- 重复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;
}