一个用算法实现的程序会耗费两种资源:处理时间和内存。很显然,一个好的算法应该耗费时间少、所用内存低,但是实际上往往不能两全其美。
算法的类型分为如下几种:
1、贪婪算法:每一步所做的都是当前最紧急、最有利的,不会考虑后果,直到完成任务。这种算法的稳定性很差,很容易带来严重成果,但是如果方向正确,该算法也是高效的。
2、分治算法:该算法就是将一个大问题分解成许多小问题,然后单独处理这些小问题,最终将结果结合起来形成对整个问题的解决方案。当子问题和总问题类型类似时,该算法很高效,递归就属于该算法。
3、回溯算法:也可以称为“排除算法”,是一种组织好的试错法。某一点如果有多个选择,则任意选择一个,如果不能解决问题则退回选择另一个,直到找到正确的选择。这种算法的效率很低,除非运气好,比如迷宫就可以使用这种算法来实现。
衡量算法是否高效主要从以下几方面分析:
1、简单性和清晰度
2、空间效率
3、时间效率
要衡量算法的效率,关注如下几个方面:
1、测量执行时间:Java中可使用System.currentTimeMillis()获得毫秒数,可在需要测量的代码前后获得开始、结束时间,两者相减就是耗费的毫秒数。
2、指令计数:指编写算法的代码,对一个算法的实现代码计算执行指令次数。
3、测量内存使用率:算法中包含的对象和引用书目,其越多则内存使用越高,反之越低。
查找算法:
(1)线性查找:从数组的第一个元素开始查找,并将其与查找值比较,如果相等则停止,否则继续下一个元素查找,直到找到匹配值。要求被查找的数组中的元素是无序的、随机的。
static boolean linearSearch(int target,int[] array){
int len=array.length;
for(int i=0;i<len;i++){
if(array[i]==target){
return true;
}
}
return false;
}
(2)二分查找:假设被查找数组中的元素是升序排列的,那么查找时,首先会直接到数组的中间位置(数组长度/2),并将中间值和查找值比较,如果相等则返回;否则,如果当前元素值小于查找值,则继续在数组的后面一半查找,如果当前元素值大于查找值,则继续在数组的前面一半查找,直到找到目标值或者无法再二分数组时停止。二分查找只是针对有序排列的各种数组或集合。
static boolean binarySearch(int target,int[] array){
int front=0;
int tail=array.length-1;
//判断子数组是否能再次二分
while(front<=tail){
int middle=(front+tail)/2;
if(array[middle]==target){
return true;
}
else if(array[middle]>target){
tail=middle-1;
}
else{
front=middle+1;
}
}
return false;
}
排序算法:
(1)选择排序:首先在数组中查找最小值,如果该值不在第一个位置,那么将其和处在第一个位置的元素交换,然后从第二个位置重复此过程,将剩下元素中的最小值交换到第二个位置,当到最后一位时,数组排序结束。
static void selectionSort(int[] array){
for(int i=0;i<array.length-1;i++){
int min_idx=i;
for(int j=i+1;j<array.length;j++){
if(array[j]<array[min_idx]){
min_idx=j;
}
}
if(min_idx !=i){
int temp=array[min_idx];
array[min_idx]=array[i];
array[i]=temp;
}
}
}
假设数组大小为n,外循环共执行n-1次;那么第一次执行外循环时,内循环将执行n-1次;第二次执行外循环时内循环将执行n-2次,最后一次执行外循环时内循环将执行1次,则增长函数为:(n-1)+(n-2)+...+1=n(n-1)/2=1/2*n^2+1/2*n,即可得出复杂度为O(n^2)。当数组非常大时,用于元素交换的开销相当大。
(2)冒泡排序:若左边的值小于或等于右边的值,则这两个值的位置不变。右边的值继续和下一个值做比较,重复此操作,知道比较到最后一个值。
static void bubbleSort(int[] array){
int out,in,len;
len=array.length;
for(out=len-1;out>1;out--){
boolean flag=false;
for(in=0;in<out;in++){
if(array[in]>array[in+1]){
int temp=array[in];
array[in]=array[in+1];
array[in+1]=temp;
flag=true;
}
}
if(! flag){
break;
}
}
}
(3)插入排序:对于欲排序的元素以插入的方式寻找该元素的适当位置,以达到排序的目的。优点是利用一个个元素的插入比较将元素放入适当的位置,所以是一种很简单的排序方式。但因每次排序都要与之前已排序好的元素作比较,故需花费较长的排序时间。
static void insertSort(int[] array){
int in,out,len;
len=array.length;
for(out=1;out<len;out++){
int temp=array[out];
in=out;
while(in>0&&array[in-1]>=temp){
array[in]=array[in-1];
--in;
}
array[in]=temp;//该数据要插入的位置
}
}
递归算法:
斐波那契递归参考代码如下:
static int fibonacci(int n){
if(n<=2){
return 1;
}else{
return fibonacci(n-1)+fibonacci(n-2);
}
}