Java——数据结构和算法(二)

数据结构和算法:算法部分

一、算法概述

算法的五个特征
① 有穷性:对于任意一组合法输入值,在执行有穷步骤之后一定能结束,即:算法中的每个步骤都能在有限时间内完成。

② 确定性:在每种情况下所应执行的操作,在算法中都有确切的规定,使算法的执行者或阅读者都能明确其含义及如何执行。并且在任何条件下,算法都只有一条执行路径。

③ 可行性:算法中的所有操作都必须足够基本,都可以通过已经实现的基本操作运算有限次实现之。

④ 有输入:作为算法加工对象的量值,通常体现在算法当中的一组变量。有些输入量需要在算法执行的过程中输入,而有的算法表面上可以没有输入,实际上已被嵌入算法之中。

⑤ 有输出:它是一组与“输入”有确定关系的量值,是算法进行信息加工后得到的结果,这种确定关系即为算法功能。

二、递归思想

递归,就是在运行的过程中调用自己。

递归必须要有三个要素:

  (1)边界条件
  (2)递归前进段
  (3)递归返回段

当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
 
2.1. 求一个数的阶乘:n!

/**
  * n! = n*(n-1)!
  *
  * 0!=1  1!=1
  * 负数没有阶乘,如果输入负数返回-1
  * @param n
  * @return
  */
 public static int getFactorial(int n){
     if(n >= 0){
         if(n==0){
             System.out.println(n+"!=1");
             return 1;
         }else{
             System.out.println(n);
             int temp = n*getFactorial(n-1);
             System.out.println(n+"!="+temp);
             return temp;
         }
     }
     return -1;
 }

2.2. 递归的二分查找

有序数组array[]中(前提),不断将数组的中间值(mid)和被查找的值比较,如果被查找的值等于array[mid],就返回下标mid; 否则,就将查找范围缩小一半。如果被查找的值小于array[mid], 就继续在左半边查找;如果被查找的值大于array[mid], 就继续在右半边查找。 直到查找到该值或者查找范围为空时, 查找结束。

public static int search(int[] array,int key,int low,int high){
      int mid = (high-low)/2+low;
      if(key == array[mid]){//查找值等于当前值,返回数组下标
          return mid;
      }else if(low > high){//找不到查找值,返回-1
          return -1;
      }else{
          if(key < array[mid]){//查找值比当前值小
              return search(array,key,low,mid-1);
          }
          if(key > array[mid]){//查找值比当前值大
              return search(array,key,mid+1,high);
          }
      }
      return -1;
  }
三、排序算法

排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程。

3.1.排序的分类

   1) 内部排序: 指将需要处理的所有数据都加载到内部存储器中进行排序。
   2) 外部排序: 数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。

常见的排序算法分类(见下图):
在这里插入图片描述
这里总结出自己学过的排序及代码:

3.2 冒泡排序

介绍: 冒泡排序的原理非常简单,它重复地走访过要排序的数列,一次比较两个元 素,如果他们的顺序错误就把他们交换过来。
排序思想:

 1. 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。 
 2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步 做完后,最后的元素会是最大的数。 
 3. 针对所有的元素重复以上的步骤,除了最后一个。 
 4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要 比较为止。
//冒泡排序
public static int[] bubbleSort(int[] arr) {
	for(int i = arr.length-1 ; i > 0  ; i--) {//比较的次数时递减的
		for(int j = 0 ; j < i; j++) {//控制要比较的元素 元素的 个数是随着比较的次数变换的
			//比较相邻的两个元素  
			if(arr[j] > arr[j + 1]) {//如果左边的大于右边 则需要交换两个元素的位置
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
	return arr;
}

3.3 快速排序

排序思想:

 1. 从数列中挑出一个元素,称为"基准"(pivot)
 2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
 3. 在这个分区结束之后, 该基准就处于数列的中间位置。这个称为分区(partition)操作。 
 4. 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。 
// 快速排序算法
	public static void quickSort(int[] array,int left,int right){
		
		int start = left;
		int end = right;
		int key = array[start];  //基准元素
		
		while(start < end){  //对于传入的参数要判断 不能交叉越界
		    // 从右往左找 while结束 就是找见比基准小的元素
			while (start < end && array[end] > key) {  
				end--;
			}
			while (start < end && array[start] < key) {
				start++;
			}
			if (start <end && array[start]==array[end]) {
				start++;
			}else {
				int temp = array[start];
				array[start] = array[end];
				array[end] = temp;
			}
		}
		
		if (end - 1 > left) {  //对左半部分进行递归排序
			quickSort(array, left, end-1);
		}
		if (start + 1 < right) {
			quickSort(array, start+1, right);
		}
	}

3.4 选择排序

选择排序是一种简单直观的排序算法。

工作原理为:在未排序的序列中找出最小(大)元素与第一个位置的元素交换位置

注意选择排序与冒泡排序的区别:冒泡排序通过依次交换相邻两个顺序不合法的元素位置,从而将当前最小(大)元素放到合适的位置;而选择排序每遍历一次都记住了当前最小(大)元素的位置,最后仅需一次交换操作即可将其放到合适的位置。然后在剩下的元素中再找最小(大)元素与第二个元素的位置交换,依此类推,直到所有元素排序排序完成。

根据上述描述,一共进行n-1趟比较后,就能完成整个排队过程。我们可以知道,第k趟比较需要进行的数组元素的两两比较的次数为n-k次,所以共需要的比较次数为n*(n-1) / 2,因此选择排序算法的时间复杂度与冒泡排序一样,也为O(n^2)

算法思想:

 1.初始状态:序列为无序状态。
 2.第1次排序:从n个元素中找出最小(大)元素与第1个记录交换
 3.第2次排序:从n-1个元素中找出最小(大)元素与第2个记录交换
 4.第i次排序:从n-i+1个元素中找出最小(大)元素与第i个记录交换
 5.以此类推直到排序完成
// 选择排序
public static void choiceSort(int[] array){
	
	for (int i = 0; i < array.length; i++) {
		int minIndex = i; //minIndex 记录最小的元素所在的位置 假设每次开始的位置位最小元素
		for (int j = i; j < array.length; j++) {
			if (array[j] < array[minIndex]) {
				minIndex = j;
			}
		}
		int temp = array[i];
		array[i] = array[minIndex];
		array[minIndex] = temp;
	}
}

3.5 插入排序

对于n个元素,一共需要进行n-1轮比较,
而第k轮比较需要进行k次数组元素的两两比较,
因此共需要进行的比较次数为:1 + 2 + … + (n-1),
所以插入排序的时间复杂度同冒泡排序一样,也为O(n^2)

算法思想:

 1.从第一个元素开始,该元素可认为已排序。
 2.取出下一个元素,在排序好的元素序列中从后往前扫描
 3.如果元素(已排序)大于新元素,将该元素移到下一位置
 4.重复 3步骤 直到找到已排序的元素小于或等于新元素的位置
 5.将新元素插入该位置后
 6.重复2-5直到排序完成
// 插入排序
	public static void insertSort(int[] array){
		
		for (int i = 0; i < array.length-1; i++) {
			for (int j = i+1; j > 0; j--) {
				if (array[j] < array[j-1]) {
					int temp = array[j];
					array[j] = array[j-1];
					array[j-1] = temp;
				}else{  // 当后边的元素比前边的元素大或相等 不要交换 直接结束循环
					break;
				}
			}
		}
	}

3.6 排序算法性能对比
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值