zoukankan      html  css  js  c++  java
  • 用分解的方式学算法001——选择排序

    我们在学习算法时,经常遇到的一个问题是,看的懂但是写不出来。究其原因,是没有理解到位。

    那么怎么才能理解到位呢?我认为关键是“分解”,就是把算法中的节点按层次和步骤分解出来。

    一步一步的实现。

    今天先来分解一下排序算法中的一个算法——选择排序。

    为什么叫选择排序呢?

    一种最简单的排序算法是这样的:首先,找到数组中最小的那个元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小的元素那么它就和自己交换)。再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。如此往复,直到将整个数组排序。这种方法叫做选择排序。

    可以发现,选择排序的关键点就是选择“最小值”。这个名称,就是这个算法的核心思想。我们先来看一个完整的算法的实现。

            ///选择排序
    	public static void SelectSort0(int[] a){
    		int min=0;
    		for(int i=0;i<a.length;i++){
    			min=i;
    			for(int j=i+1;j<a.length;j++){
    				if(a[min]>a[j]){
    					min=j;
    				}
    			}
    			int tmp=0;
    			tmp=a[i];
    			a[i]=a[min];
    			a[min]=tmp;
    		}
    		
    		for(int i=0;i<a.length;i++){
    			System.out.print(a[i] + " ");
    		}
    	}
    

     这个算法,看完之后比较容易懂,但是不好记。下面我就用分解的方式来对这个算法进行拆解。

    第一步:找最小值(索引)

    给定一个数组,从中找到第一次出现的最小的值(其索引),这个算法要如何实现呢?

    我想用一个循环就可以搞定,代码如下:

    	public static int FindMinIndex(int[] a){
    		int min=0;
    		for(int i=0;i<a.length;i++){
    			if(a[min]>a[i]){
    				min=i;
    			}
    		}
    		return min;
    	}
    

    选择排序的思想就是每次遍历,找到当先序列的最小的索引,和当前的起始索引的元素进行交换。

    因此我们需要一个可以自己指定“起始索引”的重载版本:

    	public static int FindMinIndex(int[] a,int beginIndex){
    		int min=beginIndex;
    		for(int i=beginIndex;i<a.length;i++){
    			if(a[min]>a[i]){
    				min=i;
    			}
    		}
    		return min;
    	}
    

     其中,第二个参数,是数组a的起始遍历的索引。

    第二步:交换索引元素

    这个很简单,直接上代码

    	public static void Exchange(int[] a,int i,int j){
    		int temp=a[i];
    		a[i]=a[j];
    		a[j]=temp;
    	}
    

    第三步:进行组合

    在选择排序的主方法中,对数组进行一次遍历。每次遍历,找到最小的值的元素对应的索引,和当前的起始索引的元素进行交换。遍历完毕,则数组排序完毕。

    	public static void SelectSort(int[] a){
    		for(int i=0;i<a.length;i++){
    			int beginIndex=i;
    			int min = FindMinIndex(a,beginIndex);
    			Exchange(a,min,i);
    		}
    	}
    

     完整代码如下:

    package asen.yang;
    
    public class selectSort {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		int[] a={5,1,4,8,3,9,0,2,7,6,1,2,5};
    		
    		SelectSort(a);
    		for(int i=0;i<a.length;i++){
    			System.out.print(a[i]+ " ");
    		}
    	}
    	
    	
    	public static int FindMinIndex(int[] a){
    		int min=0;
    		for(int i=0;i<a.length;i++){
    			if(a[min]>a[i]){
    				min=i;
    			}
    		}
    		return min;
    	}
    	
    	public static int FindMinIndex(int[] a,int beginIndex){
    		int min=beginIndex;
    		for(int i=beginIndex;i<a.length;i++){
    			if(a[min]>a[i]){
    				min=i;
    			}
    		}
    		return min;
    	}
    	
    	public static void Exchange(int[] a,int i,int j){
    		int temp=a[i];
    		a[i]=a[j];
    		a[j]=temp;
    	}
    	
    	public static void SelectSort(int[] a){
    		for(int i=0;i<a.length;i++){
    			int beginIndex=i;
    			int min = FindMinIndex(a,beginIndex);
    			Exchange(a,min,i);
    		}
    	}
    	
    	///选择排序
    	public static void SelectSort0(int[] a){
    		int min=0;
    		for(int i=0;i<a.length;i++){
    			min=i;
    			for(int j=i+1;j<a.length;j++){
    				if(a[min]>a[j]){
    					min=j;
    				}
    			}
    			int tmp=0;
    			tmp=a[i];
    			a[i]=a[min];
    			a[min]=tmp;
    		}
    		
    		for(int i=0;i<a.length;i++){
    			System.out.print(a[i] + " ");
    		}
    	}
    
    }
    

     在学习算法时,如果对最终的代码记不清楚,那可以尝试使用分解的方式,记住其关键点。然后再组合。

    而对于向排序这样的经典算法,几乎所有的开发语言的类库中都已经实现了。我们学习的目的,并不仅仅是重复已经实现的东西,更重要的是在学习中,掌握思想。而思想,更多的体现在其中的关键点上。因此对算法进行分解,找准关键点,理解核心思想,才是学习算法时,所更应该重点关注的角度。

    接下来会按照这个思路,进行其他算法的分解。从这个角度,在学习算法的过程中,会有更多的收获。

  • 相关阅读:
    luogu P1613 跑路
    luogu P2047 社交网络
    luogu P2740 [USACO4.2]草地排水Drainage Ditches
    「字典树」最大异或对
    「贪心」耍杂技的牛
    「贪心」士兵
    「贪心」糖果传递
    「几何」[USACO12DEC]疯狂的栅栏Crazy Fences
    「LCA」[USACO10HOL]牛的政治Cow Politics
    「二分答案 + 前缀和」防线
  • 原文地址:https://www.cnblogs.com/asenyang/p/8794322.html
Copyright © 2011-2022 走看看