您的位置:首页 > 职场人生

黑马程序员 常用的一些小算法

2013-07-01 21:34 281 查看
---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------冒泡排序:

原理(以升序为例):冒泡排序的方法其实就是挨个比较每次比较选出大地一方,并把它置于比较项中偏后的位置,这样依次比较直至比较到最后一个元素最终每次比较后的最后一个位置都是此次比较中值最大的一个,当比较全部完成时,升序排列就完成了。简单举一个例子:有一个一维数组,有五个元素。当我们使用冒泡排序的时候第一次的比较就是第一个元素跟第二个元素,如果第二个元素比第一个元素要大则二者的值相互交换,这样保证了后一个值比前一个大,完成之后继续进行比较,就是第二个跟第三个进行比较(也就是第一轮中得到的较大的值跟第三个比较,不过就是定下了个规则比较出来的较大的值必须放置在角标大的位置上也就是紧挨着下一个要比较的值的前一个位置)比较方式同第一第二比较一样,如果第三的值小于第二个的值,则互换值,否则不变,继续第三个跟第四个的比较,直至比较到第五个,最终第五个位置上的之就是这个组数组中的最大值。第一轮比较完之后进行第二轮的比较,选出第二大的值,比较过程就是第一跟第二比较,第二跟第三比较,第三跟第四比较,最终第四个位置上的就是第二大的值也就是第二轮比较出来的最大值(第四跟第五无需比较,因为第一轮比较得出的第五位置上的值就是这组数中的最大值)。之后进行第三轮比较第四轮比较,一直比较到只剩下第一第二两个位置上的值没有确定大小时,在进行一次比较,这样就得到了原数组的升序数组。从上面的来看很明显这时一个大圈套小圈的方式(循环嵌套)实现代码样例如下:
public static void bubbleSort(int[] arr)
{
for (int x = 0;x<arr.length-1 ; x++)//控制的是内循环的循环次数
{
for (int y = 0;y<arr.length-x-1 ;y++ )//进行冒泡排序比较
{
if(arr[y]>arr[y+1])
swap(arr,y,y+1);
}
}
}
public static void swap (int [] arr,int a, int b)
{
int temp;
temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}

选择排序:

原理:(升序为例)选择排序的原理就是:升序排序后的数组中的0角标对应的位置(数组角标是从0开始的)的值就是这组数组中值最小的数,角标为1的对应的就是第二小的值,或者说角标越大的位置对应的值越大。比较的方法就是拿当前数组中的第一个角标位置的上所对应的的值不确定是否是当前位置应放置的那个值与其后的所有值相比较,得出的最小值就放置在这个角标对应的位置。举例来说,一个数组第一次选择排序的时候,第一个不确定的位置就是0角标位置,也就是第一个值,用这个值跟其他后续角标对应位置的值依次相比,选出最小的,放置在0角标位置即可。第二次比较时不确定的位置就是角标为1的位置,继续进行第二轮的比较,直至进行到完全的比较结束。最终就得到了升序的数组。

    在我们比较过程中,有两种方法可以选择:第一种直接拿角标中的值进行比较,如果被比较的值小于了比较值则两个位置的值对换,即保证比较位置上的(角标较小的位置)值是最小的。这样比较一次交换一次。第二种方法,找到一个记录最小值的变量,因为我们的最终目的是角标越小对应的值越小,所以我们可以记录下每轮比较的至最小的角标,到比较结束后再进行角标中值得对换,这样每次比较只进行了一次对换,提高了程序的运行效率。实例:

public static void selectSort(int [] arr)
{
for (int x = 0;x<arr.length ;x++ )
{
int min = x;
for (int y = x+1;y<arr.length ;y++ )
{
if (arr[min] >arr[y])
{
min = y;
}
}
if (min !=x)
{
swap (arr,min,x);
}

}

}

折半查找(二分查找)

使用前提:查找的数组是有序的。

原理:(假设给出的数组是升序的)因为数组是有序的,所以我们查找的时候可以每次查看选出的一半中的中间位置对应的值是否为我们想要查看的值,是:查找结束,否:1.大于查找值:下次的查找区间就是本次区间的开始位置到本次查看的位置-1的位置(查看的位置已经比较过了不是要查看的值,故-1);2.小于查找的值:下查找的区间就是本次查看的位置+1到本次查看的区间的末尾位置。这样依次进行,每次的查找范围都缩小了一半。

注意项:因为数组的角标是从0开始的,所以确定中间角标时需要注意下。实例:

class ErFen 

{
public static void main(String[] args) 
{
int[] arr =new int[]{1,2,3,4,5,6,7};
//int x = 9;
int x = 7;
System.out.println("x="+x);
for (int i = 0;i<arr.length ;i++ )
{
if (i == 0)
System.out.print("{"+arr[0]+",");
else if (i==arr.length-1)
{
System.out.println(arr[i]+"}");
}
else
System.out.print(arr[i]+",");

}
halfSort(arr,x);
}
public static void halfSort(int[] arr,int x)
{
int start = 0;
int end = arr.length-1;
int mid = (arr.length-1)/2;
while(end>=start)
{
if(arr[mid]!=x)
{
if(arr[mid]>x)
end = mid-1;
else
start = mid+1;
mid = (start + end)/2;
}
else
break;

}
if(end>=start)
System.out.println("与x相等的值是:arr["+mid+"]="+arr[mid]);
else
System.out.println("没有查到与x相等值!");
}

}

递归:

原理:自身调用自身进行计算;

需要注意的事项:递归结束条件,调用自身部分书写。只要掌握好这两点递归就搞定了,而这两点也是递归的最大难点。由于递归这个玩意太抽象,所以拿实例讲解才是最容易理解的。

Eg:猴子吃桃问题:猴子摘了N个桃子,第一天吃了一半,还不过瘾,就又吃了一个,第二天又将剩下的桃子吃掉了一半,又多吃了一个。以后每天都是吃了剩下的一半多一个,直到第十天想吃的时候就剩下一个桃子了,就第一天共摘下了多少个桃子?

分析:由题可知当天的总量= (下一天的总量+1)*2;

这里有两种思路:

第一种逆向思路从第十天开始算循环十次,代码:

int sum = 0;
for (int day = 10;day>0;day-- )
{
if(day ==10 )
sum =1;
else
sum = (sum+1)*2;
}

第二种正向思维,也就是我们要用的递归算法:

 

Day 当天桃子数
  

1 Sum1 = (sum2 + 1)*2  

2 Sum2 = (sum3 + 1)*2  

3 Sum3 = (sum4 + 1)*2  

4 Sum4 = (sum5 + 1)*2  

5 Sum5 = (sum6 + 1)*2  

6 Sum6 = (sum7 + 1)*2  

7 Sum7 = (sum8 + 1)*2  

8 Sum8 = (sum9 + 1)*2  

9 Sum9 = (sum10 + 1)*2  

10 Sum10 = 1
 

由表我们可以得出的结论:当day != 10的时候:第n天的桃子总数 = (第n+1天的桃子总数+1)*2

这样我们就得到了递归条件和递归内容
If (day!=10)
{
day++;
return (sum(day)+1)*2;
}
else return 1;

这样递归的算法也就得到了 所以正向思维的代码是:

class TaoZi 

{
public static void main(String[] args) 
{

int day = 1;
int sum =0;
sum = sum(1);
System.out.println("一共有"+sum+"个桃子!");
}
public static int sum(int day)
{
if(day!=10)
{
day++;
return (sum(day)+1)*2;
}
else return 1;
}

}---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  递归 折半 算法