-
给定一个递增的正整数序列a和一个正整数m,求序列中的两个不同位置的数a和b,使他们的和恰好为m,输出所有满足条件的方案。
#include <stdio.h> /* 给定一个递增的正整数序列a和一个正整数m,求序列中的两个不同位置 的数a和b,使他们的和恰好为m,输出所有满足条件的方案。 */ int main() { int a[6] = {1,2,3,4,5,6}; int i=0, j=5,m=8; 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--; } return 0; } /*运行结果 2 6 3 5 */
-
序列合并问题。假设有两个递增序列a和b,要求把他们合并成一个递增序列c.
#include<stdio.h> int merge(int a[], int b[], int c[], int n,int m) { int i=0,j=0,index = 0; while(i<n&&j<m) { if(a[i]<=b[j]) c[index++] = a[i++]; else c[index++] = b[j++]; } while(i<n) c[index++] = a[i++]; while(j<m) c[index++] = b[j++]; return index;//返回序列c的长度 } int main() { int a[5]={1,3,5,7,9}, b[4]={2,4,6,8}; int c[12]; int len = merge(a,b,c,5,4); for(int i=0; i<len; i++) { printf("%d",c[i]); if(i<len-1) printf(" "); else printf("\n"); } return 0; } //运行结果 1,2,3,4,5,6,7,8,9
-
2-路归并排序( nlogn)
例如序列{66, 12, 33, 57, 64, 27, 18}
第一趟新序列 { 12, 66, 33, 57, 27, 64, 18 }
第二趟新序列 { 12, 33, 57, 66, 18, 27, 64 }
第三趟新序列 {12, 18, 27, 33, 57, 64, 66 }
#include<stdio.h>
/*
归并排序递归实现
*/
void merge(int a[], int left1, int right1, int left2, int right2)
{
int i=left1, j = left2; // i指向a[L1],j指向a[L2]
int temp[100], index = 0; // temp临时存放合并后的数组
while(i<=right1&&j<=right2)
{
if(a[i]<=a[j]) temp[index++] = a[i++];
else temp[index++] = a[j++];
}
while(i<=right1) temp[index++] = a[i++];
while(j<=right2) temp[index++] = a[j++];
for(i=0; i<index; i++)
a[left1+i] = temp[i]; //将合并后的序列赋值回数组a
}
void mergeSort(int a[], int left, int right)
{
if(left<right) // 只要left小于right
{
int mid = (left + right)/2;
mergeSort(a, left, mid); //递归左子区间
mergeSort(a, mid+1, right); //递归右子区间
merge(a, left, mid,mid+1, right); //将左右区间合并
}
}
int main()
{
int a[7] = {66,12,33,57,64,27,18};
mergeSort(a, 0,6);
for(int i=0; i<7; i++)
{
printf("%d",a[i]);
if(i<6) printf(" ");
else printf("\n");
}
}
//运行结果 12 18 27 33 57 64 66
#include<stdio.h>
#include<algorithm>
using namespace std;
/*
归并排序非递归实现
*/
void merge(int a[], int left1, int right1, int left2, int right2) //两个序列合并
{
int i=left1, j = left2; // i指向a[L1],j指向a[L2]
int temp[100], index = 0; // temp临时存放合并后的数组
while(i<=right1&&j<=right2)
{
if(a[i]<=a[j]) temp[index++] = a[i++];
else temp[index++] = a[j++];
}
while(i<=right1) temp[index++] = a[i++];
while(j<=right2) temp[index++] = a[j++];
for(i=0; i<index; i++)
a[left1+i] = temp[i]; //将合并后的序列赋值回数组a
}
void mergeSort(int a[], int n)
{
//step为组内元素个数
//step/2 为左子区间元素个数,注意等号可以不取
for(int step=2; step/2<=n; step*=2){
//每step个元素一组,组内前step/2和后step/2元素进行合并
for(int i=0; i<n; i+=step)
{
int mid = i + step/2 - 1;//左子区间元素个数为step/2
if(mid+1<=n) //右子区间存在元素则合并
//左子区间为[i, mid], 右子区间为[mid+1,min(i+step-1, n)]
merge(a,i, mid, mid+1, min(i+step-1, n));
}
for(int i=0; i<7; i++)
{
printf("%d",a[i]);
if(i<6) printf(" ");
else printf("\n");
}
}
}
int main()
{
int a[7] = {66,12,33,57,64,27,18};
mergeSort(a, 6);
}
//运行结果 12 18 27 33 57 64 66
4. 快速排序( nlogn)
#include<stdio.h>
#include<algorithm>
#include<stdlib.h>
#include<time.h>
#include<math.h>
using namespace std;
/*
快速排序
*/
//对区间[left, right]进行一次划分
int Partition(int a[], int left, int right)
{
//生成[left,right]内的随机数
int p = (round(1.0*rand()/RAND_MAX*(right-left)+left));
swap(a[p], a[left]);//交换a[p]和a[left]
int temp = a[left]; //以a[left]为枢轴
while(left<right) //只要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]挪到a[right]
}
a[left] = temp; //把temp放到left与right相遇的地方
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[7] = {66,12,33,57,64,27,18};
quickSort(a, 0, 6);
for(int i=0; i<7; i++)
printf("%d ", a[i]);
}
//运行结果 12 18 27 33 57 64 66
5. 随机选择算法(O(n))
(408真题)给定一个由整数组成的集合,集合中的整数各不相同,现在要将它分为两个子集合,使得这两个子集合的并为原集合,交为空集,同时在两个子集合的元素个数n1和n2之差的绝对值|n1-n2|可能小的前提下,要求他们各自的元素之和s1与s1之差的绝对值|s1-s2|尽可能大。求这个|s1-s2|等于多少?
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<stdlib.h>
#include<time.h>
/*
如何从一个无序的数组中求出第K大的数,(假设数组中的数各不相同)
随机选择算法 O(n)
*/
using namespace std;
int a[6];
//随机划分
int randPartition(int a[], int left, int right)
{
//生成[left,right]内的随机数
int p = (round(1.0*rand()/RAND_MAX*(right-left)+left));
swap(a[p], a[left]);//交换a[p]和a[left]
int temp = a[left]; //以a[left]为枢轴
while(left<right) //只要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]挪到a[right]
}
a[left] = temp; //把temp放到left与right相遇的地方
return left;//返回相遇的下标
}
int randSelect(int a[], int left, int right, int k)
{
if(left==right) return a[left];//边界
int p = randPartition(a, left, right);//随机划分
int m = p-left+1;
if(k==m) return a[p];
if(k<m) //第k大的数在主元左侧
return randSelect(a,left, p-1,k);
else
return randSelect(a, p+1, right, k-m);
}
int main()
{
srand((unsigned)time(NULL));
int n;
int sum=0, sum1=0;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
randSelect(a,0,n-1, n/2);//寻找第n/2的数,并进行切分
for(int i=0; i<n/2; i++)
sum1+=a[i];
printf("%d\n",(sum-sum1)-sum1);
return 0;
}
/*
13
1 6 33 18 4 0 10 5 12 7 2 9 3
80
*/