算法期末复习(一)

算法总结

1、蛮力法

直接粗暴,就行循环。例如:
选择排序:利用循环每次选出最小的数依次放在序列最前面,时间复杂度为 O(n^2),具有不稳定性。
代码如下:

#include
using namespace std;
#define N 7
//选择排序(蛮力法,每次选出最小的放在最前面)
void selectSort(int a[]) {
 for(int i=0;i<N-1;i++) {
  int k = i;//临时存放最小值
  for(int j=i+1;j<N;j++) {
   if(a[k]>a[j]) {
    k = j;
   }
  }
  int t = a[i];//将最小值放在 i 的位置
  a[i] = a[k];//即交换a[i] 和 a[j] 的值
  a[k] = t;
 }
}
int main() {
 int a[] = {8,2,7,0,3,6,5};
 selectSort(a);
 for(int i=0;i<N;i++)
  cout<<a[i]<<" ";
 cout<<endl;
 getchar();
 return 0;
}

冒泡排序:利用循环依次比较相邻两个数的大小,每次将最大的数沉淀下来,即放在序列末尾。时间复杂度为 O(n^2),具有稳定性。
代码如下:

#include
using namespace std;
#define N 7
//冒泡排序(蛮力法,相邻两个数之间的比较,每次选出最大的数放在最后)
void bubbleSort(int a[]) {
 for(int i=0;i<N;i++) {//外层循环,比较轮数
  for(int j=0;j<N-1-i;j++) {//内层循环,相邻的比较
   if(a[j]>a[j+1]) {
    int t = a[j];
    a[j] = a[j+1];
    a[j+1] = t;//交换,将最大的沉淀下来
   }
  }
 }
}
int main() {
 int a[] = {8,2,7,0,3,6,5};
 bubbleSort(a);
 for(int i=0;i<N;i++)
  cout<<a[i]<<" ";
 cout<<endl;
 getchar();
 return 0;
}

最大连续子序列问题:利用循环依次求前面所有数据从规定起点开始的和,若和为负,则令其为零,否则求最大连续子序列和。

#include
using namespace std;
#define R 6
//最大连续子序列问题
int maxsubSum(int a[]) {
 int maxSum = 0;//最大连续子序列
 int thisSum = 0;//本次求和
 for(int i=0;i<R;i++) {
  thisSum += a[i];
  if(thisSum < 0)
   thisSum = 0;
  if(thisSum > maxSum)
   maxSum = thisSum;//最大连续子序列
 }
 return maxSum;
}
int main() {
 int a[] = {-2,11,-4,13,-5,-2};
 cout<<"最大连续子序列为:"<<maxsubSum(a);
 getchar();
 return 0;
}

2、递归

将一个问题拆分为相似的子问题,递归需要有出口,否则会陷入死循环,在遇到出口之前让反复执行这个程序即可。递归的空间复杂度大,是一个以空间换时间的算法,不适用于太过庞大的数据。
fibonacci 数列:fibonacci 数列是一个规律性很强的数列,从第三位数起,该数是前两个数的和,即:1,1,2,3,5,8,13……,递归性很强。

#include
using namespace std;
int fib(int n) {
 if(n>2)
  return fib(n-1) + fib(n-2);
 else
  return 1;//出口
}
int main() {
 cout<<fib(1)<<" "<<fib(2)<<" "<<fib(3)<<" "<<fib(4);
 cout<<" "<<fib(5)<<" "<<fib(6)<<" "<<fib(7)<<" "<<fib(8);
 //1 1 2 3 5 8 13 21
 getchar();
 return 0;
}

排列问题:m 个数任取 n 个,不重复,m = n 时为全排列。不重复需要定义一个函数来确定,这个数据是否取过。
例如从5个数字中取5个,即 5 的全排列,我们都知道有120个,代码如下:

#include
using namespace std;
#define M 5//可选择的数字
#define N 5//取的数字
int num = 0;//记录个数
int res[N+1] = {0};//存放所取数字组合结果
//排列问题(m个数任取n个,不重复,m = n 时为全排列)
void output() {//输出函数
 for(int i=1;i<=N;i++)
  cout<<res[i]<<" ";
 cout<<endl;
}
bool isIn(int a,int pos) {//判断是否选取过
 for(int i=1;i<=pos;i++)
  if(res[i] == a)
   return true;
 return false;
}
void Rank(int pos) {
 if(pos>N) {
  num++;
  output();
  return;//出口
 }
 for(int i=1;i<=M;i++) {
  if(!(isIn(i,pos-1))) {//不在原序列中才取值
   res[pos] = i;//取值
   Rank(pos+1);//下一个
  }
 }
}
int main() {
 Rank(1);
 cout<<num<<endl;
 getchar();
 return 0;
}

3、分治法

分而治之,以某个元素为基准值分块儿,分别对两边进行处理。
快速排序:快排的关键是找到基准值,基准值的左边都是比它小的数,右边都是比它大的数。即是将比它小的数都移到它左边,比它大的数都移到右边。

#include
using namespace std;
#define N 9
//快速排序
int position(int a[],int start,int end) {
 int i = start,j = end;
 int tmp = a[start];//选第一个元素作为中间值
 while(i!=j) {//未相遇时进行比较
  while(i<j && a[j]>tmp) 
   //从右边开始寻找第一个比中间值小的元素
   j--;
  a[i] = a[j];
  while(i<j && a[i]<=tmp)
   //从左边开始寻找第一个比中间值大的元素
   i++;
  a[j] = a[i];
 }
 a[i] = tmp;//将中间值放回来
 return i;
}
void quickSort(int a[],int start,int end) {
 if(start<end) {//有多个元素时排序
  int i = position(a,start,end);//基准元素
  quickSort(a,start,i-1);//左边
  quickSort(a,i+1,end);//右边
 }
}
int main() {
 int a[] = {4,2,11,0,7,8,5,21,9};
 cout<<"原序列:"<<endl;
 for(int i=0;i<N;i++)
  cout<<a[i]<<" ";
 cout<<endl;
 quickSort(a,0,N-1);
 cout<<"排序后:"<<endl;
 for(int i=0;i<N;i++)
  cout<<a[i]<<" ";
 cout<<endl;
 getchar();
 return 0;
}

归并排序:先拆分,在合并,两者都是一个递归的过程。

#include
using namespace std;
#define N 9
//归并排序
void merge(int a[],int low,int mid,int high) {
 //排序
 int i = low,j = mid+1;//两个子序列的下标
 //动态分配临时数组
 int *tmp = (int*)malloc((high-low+1)*sizeof(int));
 int k = 0;//临时数组的下标
 while(i<=mid && j<=high) {
  if(a[i]<a[j])
   tmp[k++] = a[i++];
  else
   tmp[k++] = a[j++];
 }
 while(i<=mid)
  tmp[k++] = a[i++];
 while(j<=high)
  tmp[k++] = a[j++];
 for(i=low,k=0;i<=high;i++,k++)
  a[i] = tmp[k];
 free(tmp);//释放临时数组空间
}
void mergeSort(int a[],int start,int end) {
 if(start<end) {//含多个元素进行排序
  int mid = (start + end)/2;//分解
  mergeSort(a,start,mid);//左边
  mergeSort(a,mid+1,end);//右边
  merge(a,start,mid,end);//有序数组的合并
 }
}
int main() {
 int a[] = {4,2,11,0,7,8,5,21,9};
 cout<<"原序列:"<<endl;
 for(int i=0;i<N;i++)
  cout<<a[i]<<" ";
 cout<<endl;
 mergeSort(a,0,N-1);
 cout<<"排序后:"<<endl;
 for(int i=0;i<N;i++)
  cout<<a[i]<<" ";
 cout<<endl;
 getchar();
 return 0;
}

查找最大值和次大值问题:利用分治法解决即是拆分,每次找出基准值,分别找出基准值两边的最大值和次大值,该问题的出口是拆分到至多两个元素,即可依次往回求最大值和次大值。

#include
using namespace std;
#define N 9
//查找最大值和次大值问题
void maxsub(int a[],int start,int end,int *max1,int *max2) {
 if(start == end) {//一个元素
  *max1 = a[start];
  *max2 = a[end];
 }
 else if((end-start)==1) {//两个元素
  *max1 = a[start]>a[end]?a[start]:a[end];
  *max2 = a[start]>a[end]?a[end]:a[start];
 }
 else {
  int mid = (start+end)/2;
  int lmax1,lmax2;
  maxsub(a,start,mid,&lmax1,&lmax2);//左边
  int rmax1,rmax2;
  maxsub(a,mid+1,end,&rmax1,&rmax2);//右边
  if(lmax1>rmax1) {
   *max1 = lmax1;//最大值
   *max2 = lmax2 > rmax1 ? lmax2 : rmax1;//次大值
  }
  else {
   *max1 = rmax1;
   *max2 = lmax1 > rmax2 ? lmax1 : rmax2;
  }
 }
}
int main() {
 int a[] = {4,2,11,0,7,8,5,21,9};
 cout<<"原序列:"<<endl;
 for(int i=0;i<N;i++)
  cout<<a[i]<<" ";
 cout<<endl;
 int max1,max2;
 maxsub(a,0,N-1,&max1,&max2);
 cout<<"最大值:"<<max1<<endl;
 cout<<"次大值:"<<max2<<endl;
 getchar();
 return 0;
}

折半查找:建立在排序之后的基础上,在中间值的两边查找。这里用归并排序后的数据进行查找。

#include
using namespace std;
#define N 9
//折半查找
int binSearch(int a[],int start,int end,int x) {
 if(start<=end) {
  int mid = (start+end)/2;
  if(a[mid] == x)//出口
   return mid;
  else if(a[mid]>x)//左边
   return binSearch(a,start,mid-1,x);
  else//右边
   return binSearch(a,mid+1,end,x);
 }
 return -1;//未找到
}
int main() {
 int a[] = {0,2,4,5,7,8,9,11,21};
 cout<<binSearch(a,0,N-1,11)<<endl;
 getchar();
 return 0;
}

你可能感兴趣的:(算法期末复习(一))