JAVA 常用算法

  • 查找最大值
  • 冒泡排序
  • 插入排序
  • 归并排序
  • 快速排序
  • 堆排序


查找最大值


1.首先定义最大变量maxValue,并将数组第0号元素的值赋值给maxValue; 2.从数组下标为1的位置开始循环遍历数组,每遍历一次,比较元素和maxValue的大小,如果元素值比maxValue大,则交换maxValue和元素的值; 3.循环完毕之后,maxValue变量中的值就是我们要找的最大的值 代码实现: 代码实现如下:

/**
	 * 得到最大值
	 * getMaxValue 为-1表示传入的数组为空或者传入的数组长度为0
	 * @author Administrator
	 *
	 */
	private static int getMaxValue(int[] array){
		// 定义最大值临时变量
    	int maxValue = 0;
    	if(array == null || array.length == 0){
    		maxValue = -1;
    	}
    	// 初始化maxValue变量的值
    	maxValue = array[0];
    	// 循环遍历数组,每遍历一次,用maxValue和array[i]进行比较,如果array[i]比maxValue大,则将array[i]的值
    	// 赋值给maxValue变量,这样当数组被遍历完毕后,maxValue中存储的就是这个数组中最大的值
    	for(int i = 1; i < array.length; i++){
    		if(maxValue < array[i]){
    			maxValue = array[i];
    		}
    	}
    	return maxValue;
    }

冒泡排序


1.第一次数组数据前后冒泡移动:首先从数组第0号元素开始,前后两个元素值进行比较,如果前面元素值比后面元素值大,则交 换两元素的值,直至倒数第二个元素和倒数第一个元素相比较,如果倒数第二个元素值比倒数第一个元素大,则交换此两元素的值,从而找到最大的元素值,并且这个最大元素值经过上面的冒泡移动,会出现在数组的最后位置。 2.第二次数组数据前后冒泡移动:第二次数组元素前后冒泡移动步骤和第一步步调一样,只是此时数组前后比较的元素不包含数组中最后一个元素了,因为最后一个元素已经排好序,并且放在数组的最后位置。 3.第三次数组数据前后冒泡移动。。。第N此数组数据前后冒泡移动,直到整个数组数据全部排好顺序为止。 代码实现: 代码实现如下

/**
	 * 冒泡排序
	 * 这里例举的程序是升序排序
	 * @param array
	 */
	public static void bubbleSort(int[] array){
		for(int i = array.length -1; i >= 0; i--){
			for(int j = 0; j <= i -1; j++){
				if(array[j] > array[j+1] ){
					swap(array,j,j+1);
				}
			}
		}
	}
	/**
	 * 交换a变量和b变量的值
	 * @param a
	 * @param b
	 */
	private static void swap(int array[],int i,int j){
		int temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}

插入排序


通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。说得更接地气一些就是向左查找标准比较值的位置,找到了就将标准值放入对应的位置。 代码实现: 代码实现如下

/**
	 * 升序排序例子
	 * @param array
	 */
	public static void insertedSort(int[] array){
		for(int i = 1; i < array.length; i++){
			int leftIndex = i - 1;
			// 当前标准值
			int temp = array[i];
			while(leftIndex >= 0 && array[leftIndex] > temp){
			    // 这里是挪动元素位置
				array[leftIndex+1] = array[leftIndex];
				leftIndex--;
			}
			// 找出当前标准值所在位置,并将标准值放入这个位置
			array[leftIndex+1] = temp;
		}
	}

归并排序


归并排序是基于分治法思想的排序方法,归并排序将待排序的元素序列平分成两个子序列,为每一个子序列排序,然后再将他们合并成一个子序列,然后再对上面平分后的每一个子序列递归式地采用上面方式进行排序,直到将数组中的全部元素排好顺序为止。 代码实现: 代码实现如下:

//两路归并算法,两个排好序的子序列合并为一个子序列,这里是合并序列的方法
    private static void merge(int []array,int left,int mid,int right){
        int []tempArray=new int[array.length];//辅助数组
        int pointLeft=left,pointRight=mid+1,startPosition=left;//pointLeft、pointRight是检测指针,startPosition是存放指针

        while(pointLeft<=mid && pointRight<=right){
            if(array[pointLeft]<=array[pointRight]){
            	tempArray[startPosition++]=array[pointLeft++];
            }
            else{
            	tempArray[startPosition++]=array[pointRight++];
            }
        }

        while(pointLeft<=mid){
        	tempArray[startPosition++]=array[pointLeft++];//如果第一个序列未检测完,直接将后面所有元素加到合并的序列中
        } 
        while(pointRight<=right){
        	tempArray[startPosition++]=array[pointRight++];//同上
        } 

        //复制回原数组,注意:复原的范围是left到right之间的元素
        for (int i = left; i <=right; i++){
        	array[i]=tempArray[i];
        } 
    }
    /**
     * 递归调用方法定义
     * @param array
     * @param start
     * @param end
     */
    private static void realMergeSort(int [] array,int start,int end){
        if(start<end){//当子序列中只有一个元素时结束递归
            int mid=(start+end)/2;//划分子序列
            realMergeSort(array, start, mid);//对左侧子序列进行递归排序
            realMergeSort(array, mid+1, end);//对右侧子序列进行递归排序
            merge(array, start, mid, end);//合并
        }
    }
    
    /**
     * 归并排序入口方法定义
     * @param array
     */
    public static void  mergeSort(int array[]){
    	int left = 0;
    	int end = array.length - 1;
    	realMergeSort(array, left,end);
    }

快速排序


快速排序法采用分而治之的思想来进行排序,其排序原理如下:

首先找一个基准数,然后给这个基准数找位置,找的过程中,比基准数小的放在基准数左边,比基准数大的放在基准数右边,经过这样查找后,基准数就找到了自己对应的排序位置,然后再以基准数所在位置为切割点,将数组分割成2个子序列,再对这2个子系列像上面一样分别递归排序,直到将整个数组元素排好顺序为止。

代码实现: 代码实现如下:

public static void quickSort(int[] arr, int low, int high) {
		// pointLeft:左指针 ,pointRight:右指针,standValue 用来做比较的基准值
		int pointLeft, pointRight, standValue;
		if (low > high) {
			return;
		}
		pointLeft = low;
		pointRight = high;
		// standValue就是基准位
		standValue = arr[low];

		while (pointLeft < pointRight) {
			// 先看右边,依次往左递减
			while (standValue <= arr[pointRight] && pointLeft < pointRight) {
				pointRight--;
			}
			// 再看左边,依次往右递增
			while (standValue >= arr[pointLeft] && pointLeft < pointRight) {
				pointLeft++;
			}
			// 如果满足条件则交换
			if (pointLeft < pointRight) {
				int tempValue = arr[pointRight];
				arr[pointRight] = arr[pointLeft];
				arr[pointLeft] = tempValue;
			}

		}
		// 最后将基准位与i和j相等位置的数字交换
		arr[low] = arr[pointLeft];
		arr[pointLeft] = standValue;
		// 递归调用左半数组
		quickSort(arr, low, pointRight - 1);
		// 递归调用右半数组
		quickSort(arr, pointRight + 1, high);
	}

堆排序


假如有一个数组[8,7,4,5,1],将它转换为一个完全二叉树如下:
          1-8
         /     \
      2-7    3-4
      /   \
  4-5  5-1



上图 红色小号字表示树节点位置,黑体大号字表示树节点值,从上图中可以看出,任意长度的数组都可以转换为一个完全二叉树,这个时候排序就可以采用这样的思路进行了,每循环一次数组,重新将数组构建成一个大鼎树,即数组中的最大值作为完全二叉树的根节点(对应数组的0号位置),然后交换数组0号位值和最后位置的值,这样就将最大值放在数组最大位置处了,接着又以除最后一个元素外的子序列构建新的大鼎树,然后交换0号位置和子序列最后位置的值,这样的循环操作一直持续到整个数组的顺序全部排好后为止。


代码实现:

代码实现如下:

/**
	 * 排序入口方法
	 * 升序排序
	 * @param array
	 */
	public static void heapSort(int[] array){
		int length = array.length;
		for(int i = 1; i < length ; i++){
			// 每循环一次,会将最大值放在对应的位置上,所以每循环一次,相对最后位置就是length-i号位置
			int endPosition = length-i;
			// 构建大鼎堆,即最大的值放在根节点位置,即数组的0号位置处
			buildTree(array,endPosition+1);
			// 交换数组0号位置和最后位置的值,即把上面0号位置处最大值放在数组的最后面
			swapData(array,0,endPosition);
		}
	}
	/**
	 * 构建大鼎树
	 * 原理是:
	 * 首先找出 所有非叶子节点,然后从最后一个非叶子节点开始比较,比较过程中,非也在节点作为父节点,
	 * 如果左子节点 和 右子节点都存在,并且左子节点 > 右子节点,则交换左子节点和右子节点的值,然后
	 * 如果右子节点>父节点,则交换右子节点和父节点的值;如果对于父节点来说,只存在左节点并且左节点>
	 * 父节点,则直接交换左节点和父节点的值。
	 * 对于倒数第二个非叶子节点也是一样,采用和上述一样的方式,比较和交换它对应孩子节点的值,这样比
	 * 较和交换值的方式一直持续到将最大值放入根节点为止。
	 * @param array
	 * @param length
	 */
	private static void buildTree(int array[],int length){
		// 最后一个非叶子节点计算方法: lastNodeIndex = length / 2
		int lastNodeIndex = length / 2;
		// 从最后一个非叶子节点位置开始,倒序循环找出最大值,放在树的根节点
		for(int i = lastNodeIndex; i >= 1; i--){
			// 非叶子节点作为父节点
			int parentIndex = i;
			// 父节点对应的左子节点
			int leftIndex = parentIndex*2;
			// 父节点对应的右子节点
			int rightIndex = parentIndex*2 + 1;
			
			if(rightIndex <= length && array[leftIndex-1] > array[rightIndex-1]){
				// 如果右子节点位置 <= 比较序列的长度 并且 左子节点的值 > 右节点的值,则交换左子节点和右子节点的值	
				swapData(array,leftIndex-1,rightIndex-1);
				if(array[rightIndex-1] > array[parentIndex-1]){
					// 继续比较右子节点和父节点大小,如果右子节点 > 父节点,则交换父节点和右子节点的值
					swapData(array,rightIndex-1,parentIndex-1);
				}
			}else if(rightIndex <= length && array[leftIndex-1] <= array[rightIndex-1] 
			&& array[rightIndex-1] > array[parentIndex-1]){
				// 如果右子节点位置 <= 比较序列长度 并且 左子节点 <= 右子节点 
				// 并且 右子节点 > 父节点,则直接交换右子节点值和父节点值就可以了
				swapData(array,rightIndex-1,parentIndex-1);
			}else{
				// else 在这里表示父节点只存在左子节点的情况
				if(array[leftIndex-1] > array[parentIndex-1]){
					// 如果左子节点 > 父节点,则交换左子节点值和父节点值就可以了
					swapData(array,leftIndex-1,parentIndex-1);
				}
			}	
		}
		
	}
	/**
	 * 交换数组中的值
	 * @param array
	 * @param i
	 * @param j
	 */
	private static void swapData(int[] array,int i,int j){
		int temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}