算法的概念
算法是将一组输入转化成一组输出的一系列计算步骤,其中每个步骤必须能在有限时间内完成。
算法是用来解决一类计算问题的方法,具有通用性。
插入排序
插入排序采取增量式的策略,它的时间复杂度是O(n的平方)。类似于玩扑克,玩家每拿到一张牌都要插入到手中已有的牌里,使之从小到大排好序。
在对数组进行插入排序时,要将插入点之后的数据依次往后移动一个单元。代码如下
#include <iostream>
using namespace std;
#define N 5
int a[N] = { 10, 5, 2, 4, 7 };
void insertion_sort()
{
int i, j, key;
for (j = 1; j < N; j++)
{
cout<<a[0]<<a[1]<<a[2]<<a[3]<<a[4]<<endl;
key = a[j];
i = j - 1;
while (i >= 0 && a[i] > key)
{
a[i+1] = a[i];
i--;
}
a[i+1] = key;
}
cout<<a[0]<<a[1]<<a[2]<<a[3]<<a[4]<<endl;
}
int main(void)
{
insertion_sort();
return 0;
}
算法的时间复杂度分析
评价算法的好坏,一个重要的标准就是算法的时间复杂度。
在分析算法的时间复杂度时,我们更关心最坏情况而不是最好情况,理由如下:
- 最坏情况给出了算法执行时间的上界,我们可以确信,无论给什么输入,算法的执行时间都不会超过这个上界,这样为比较和分析提供了便利。
- 对于某些算法,最坏情况是最常发生的情况,例如在数据库中查找某个信息的算法,最坏情况就是数据库中根本不存在该信息,都找遍了也没有,而某些应用场合经常要查找一个信息在数据库中存在不存在。
- 虽然最坏情况是一种悲观估计,但是对于很多问题,平均情况和最坏情况的时间复杂度差不多,比如插入排序这个例子,平均情况和最坏情况的时间复杂度都是输入长度n的二次函数
归并排序
归并排序,它采取分而治之的策略,时间复杂度是O(nlgn)。
归并排序的步骤:
- Divide: 把长度为n的输入序列分成两个长度为n/2的子序列。
- Conquer: 对这两个子序列分别采用归并排序。
- Combine: 将两个排序好的子序列合并成一个最终的排序序列。
#include <iostream>
#include <algorithm>
using namespace std;
int arr[1001];
void merge_sort(int mi, int mj)
{
if(mi == mj) return;
merge_sort(mi, (mi + mj)/2);
merge_sort((mi + mj)/2 + 1, mj);
int i = mi, j = (mi + mj)/2 + 1, arrt[1001];
for(int k = mi; k <= mj; k++)
{
if(i <= (mi + mj)/2 && arr[i] <= arr[j] || j > mj)
arrt[k] = arr[i++];
else
arrt[k] = arr[j++];
}
for(int k = mi; k <= mj; k++)
arr[k] = arrt[k];
}
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++)
cin >> arr[i];
merge_sort(0, n-1);
for(int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
}
线性查找
有些查找问题要用时间复杂度为O(n)的算法来解决。这个实现是最直观和最容易想到的,但它并不是最快的算法。
int indexof(char letter)
{
int i = 0;
while (a[i] != '\0') {
if (a[i] == letter)
return i;
i++;
}
return -1;
}
折半查找
如果在一组有序的数组中进行查找,每次取中间的元素和待查找的元素比较,如果中间的元素比待查找的元素小,就说明“如果待查找的元素存在,一定位于序列的后半部分”,这样可以把搜索范围缩小到后半部分,然后再次使用这种算法迭代。这种“每次将搜索范围缩小一半”的思想称为折半查找。
#include<stdio.h>
#include<stdlib.h>
int binFind(int A[],int len,int x) //折半查找
{
if(A == NULL)
exit(1);
else
{
int low = 0,high = len-1;//low用来记录低下标,high用来记录高下标
int mid;//low值为中间下标,用来与x比较(因此成为折半查找)
while(low <= high)
{
mid = ((low + high)/2);
if(A[mid]<x)//如果x大于中间值,则x一定在右半段
{
low = mid+1;//改变低下标为中间下标的下一个
mid = (low + high)/2;
}
else if(A[mid]>x)//如果x小于中间值,x一定存在于左半段
{
high = mid-1;//改变高下标为中间下标的前一个
mid = (low + high)/2;
}
else
return mid;//否则,x与当前中间值相等,则返回中间下标
}
}
return -1;
}
int main()
{
int arr[] = {1,2,3,5,9,15,36,46,78,95};
int ph = 0,item = 0;
for(int i = 0;i<sizeof(arr)/sizeof(arr[0]);i++)
printf("%d ",arr[i]);
printf("\n请输入要查找的值:");
scanf("%d",&item);
ph = binFind(arr,sizeof(arr)/sizeof(arr[0]),item);
if(-1 != ph)
printf("a[%d] = %d\n",ph,arr[ph]);
else
printf("没有找到%d\n",item);
return 0;
}