数据结构Java03【算法(时间复杂度、空间复杂度),排序(冒泡、快速、插入、希尔、选择、归并、基数、队列基数)】

目   录

P19-3.1算法的时间复杂度和空间复杂度

1、时间复杂度

1.1、忽略常数

1.2、忽略低次项

1.3、忽略系数

2、衡量一个算法的优劣(时间复杂度、空间复杂度)

2.1、语句频度T(n)

2.2、时间复杂度

2.3、常见的时间复杂度

2.4、时间复杂度

2.5、平均时间复杂度和最坏时间复杂度

P20-3.2排序算法之冒泡排序

P21-3.3排序算法之快速排序

P22-3.4排序算法之插入排序

P23-3.5排序算法之希尔排序

P24-3.6排序算法之选择排序

P25-3.7排序算法之归并排序

P26-3.8排序算法之基数排序

P27-3.9基数排序之队列实现


P19-3.1算法的时间复杂度和空间复杂度

1、时间复杂度

1.1、忽略常数

1.2、忽略低次项

1.3、忽略系数

2、衡量一个算法的优劣(时间复杂度、空间复杂度)

一、事后统计的方法

二、事前分析估算的方法

 

计算1-100所有数字之和

2.1、语句频度T(n)

一个算法中的语句执行次数称为语句频度,记为T(n)。

2.2、时间复杂度

 一般情况下,算法中的基本操作语句的重复执行次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n) / f(n) 的极限值为不等于零的常数,则称f(n)T(n)的同数量级函数。记作 T(n)=( f(n) ),称O( f(n) )  为算法的渐进时间复杂度,简称时间复杂度。

T(n) 不同,但时间复杂度可能相同。 如:T(n)=n²+5n+6 T(n)=3n²+3n+2 它们的T(n) 不同,但时间复杂度相同,都为O(n²)。

2.3、常见的时间复杂度

常数阶O(1)

对数阶O(log2n)

线性阶O(n)

线性对数阶O(nlog2n)

平方阶O(n2)

立方阶O(n3)

k次方阶O(nk)

指数阶O(2n)

随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。

2.4、时间复杂度

计算时间复杂度的方法:

用常数1代替运行时间中的所有加法常数 

修改后的运行次数函数中,只保留最高阶项 

去除最高阶项的系数

2.5、平均时间复杂度和最坏时间复杂度

平均时间复杂度是指所有可能的输入实例均以等概率出现的情况下,该算法的运行时间。

最坏情况下的时间复杂度称最坏时间复杂度。一般讨论的时间复杂度均是最坏情况下的时间复杂度。 这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限,这就保证了算法的运行时间不会比最坏情况更长。

P20-3.2排序算法之冒泡排序

package demo4;

import java.util.Arrays;

public class BubbleSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 5, 7, 2, 9, 4, 1, 0, 5, 7 };
		System.out.println(Arrays.toString(arr));
		bubbleSort(arr);
		System.out.println(Arrays.toString(arr));
	}
	
	/**冒泡排序 
	 * 共需要比较length-1轮
	 * 5,7,2,9,4,1,0,5,7	【5、7】	
	 * 5,7,2,9,4,1,0,5,7	【7、2】
	 * 5,2,7,9,4,1,0,5,7	...
	 * 5,2,7,4,1,0,5,7,9
	 * 2,5   
	 */
	public static void bubbleSort(int[] arr) {
		// 控制共比较多少轮
		for (int i = 0; i < arr.length - 1; i++) {
			// 控制比较的次数
			for (int j = 0; j < arr.length - 1 - i; j++) { // 减i,比较过的数字,不再进行比较
				if (arr[j] > arr[j + 1]) {
					int temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
				}
			}
		}
	}
	
	// 冒泡排序优化
	public static void bubbleSort2(int[] arr) {
		// 控制共比较多少轮
		for (int i = 0; i < arr.length - 1; i++) {
			boolean flag = false;
			// 控制比较的次数
			for (int j = 0; j < arr.length - 1 - i; j++) { // 减i,比较过的数字,不再进行比较
				if (arr[j] > arr[j + 1]) {
					int temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
					flag = true; // 加入标记					
				}
			}
			if(flag) { // 如果没有交换过元素,则已经有序!
				return;
			}
		}
	}
	
}

冒泡排序优化https://blog.csdn.net/hansionz/article/details/80822494 

P21-3.3排序算法之快速排序

设定一个基准数a。【通常取第一个数字!】

比a大的数字,往右移动;比a小的数字,往左移动!递归!!!

设置 前后 2个 标记,标记重合,进行下一次 递归!【递归结束条件:开始位置==结束位置】

package demo4;

import java.util.Arrays;

public class QuickSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 3, 4, 6, 7, 2, 7, 2, 8, 0, 9, 1 };
		quickSort(arr, 0, arr.length - 1);
		System.out.println(Arrays.toString(arr));
	}

	public static void quickSort(int[] arr, int start, int end) {
		if (start < end) {
			// 把数组中的第0个数字做为标准数
			int stard = arr[start];
			// 记录需要排序的下标
			int low = start;
			int high = end;
			// 循环找比标准数大的数和比标准数小的数
			while (low < high) {
				// 右边的数字比标准数大
				while (low < high && stard <= arr[high]) {
					high--;
				}
				// 使用右边的数字替换左边的数
				arr[low] = arr[high];
				// 如果左边的数字比标准数小
				while (low < high && arr[low] <= stard) {
					low++;
				}
				arr[high] = arr[low];
			}
			// 把标准数赋给低所在的位置的元素
			arr[low] = stard;
			// 处理所有的小的数字
			quickSort(arr, start, low);
			// 处理所有的大的数字
			quickSort(arr, low + 1, end);
		}
	}

}

P22-3.4排序算法之插入排序

认为所有的数字,都是有序的。将数字依次往前移动,一个一个插入到前面的有序序列中!

第2个数字开始取!

package demo4;

import java.util.Arrays;

public class InsertSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 5, 3, 2, 8, 5, 9, 1, 0 };
		insertSort(arr);
		System.out.println(Arrays.toString(arr));
	}

	// 插入排序
	public static void insertSort(int[] arr) {
		// 遍历所有的数字【从第2个数字开始比较!】
		for (int i = 1; i < arr.length; i++) {
			// 如果当前数字比前一个数字小
			if (arr[i] < arr[i - 1]) {
				// 把当前遍历数字存起来
				int temp = arr[i];
				int j;
				// 遍历当前数字前面所有的数字
				for (j = i - 1; j >= 0 && temp < arr[j]; j--) {
					// 把前一个数字赋给后一个数字
					arr[j + 1] = arr[j];
				}
				// 把临时变量(外层for循环的当前元素)赋给不满足条件的后一个元素
				arr[j + 1] = temp;
			}
		}
	}

}

P23-3.5排序算法之希尔排序

将 数组 分为 4部分,每一部分都进行插入排序!

第1轮步长:4;【9/2 == 4】

第2轮步长:2;【4/2 == 2】

第3轮步长:1。【2/2 == 1】

package demo4;

import java.util.Arrays;

public class ShellSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 3, 5, 2, 7, 8, 1, 2, 0, 4, 7, 4, 3, 8 };
		System.out.println(Arrays.toString(arr));
		shellSort(arr);
		System.out.println(Arrays.toString(arr));
	}

	public static void shellSort(int[] arr) {
		int k = 1;
		// 遍历所有的步长
		for (int d = arr.length / 2; d > 0; d /= 2) {
			// 遍历所有元素
			for (int i = d; i < arr.length; i++) {
				// 遍历本组中所有的元素
				for (int j = i - d; j >= 0; j -= d) {
					// 如果当前元素大于加上步长后的那个元素
					if (arr[j] > arr[j + d]) {
						int temp = arr[j];
						arr[j] = arr[j + d];
						arr[j + d] = temp;
					}
				}
			}
			System.out.println("第" + k + "次排序结果:" + Arrays.toString(arr));
			k++;
		}
	}

}

P24-3.6排序算法之选择排序

从第1个数字,开始往后找。

从第2个数字,开始往后找。

从第3个数字,开始往后找。

package demo4;

import java.util.Arrays;

public class SelectSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 3, 4, 5, 7, 1, 2, 0, 3, 6, 8 };
		selectSort(arr);
		System.out.println(Arrays.toString(arr));
	}

	// 选择排序
	public static void selectSort(int[] arr) {
		// 遍历所有的数
		for (int i = 0; i < arr.length; i++) {
			int minIndex = i;
			// 把当前遍历的数和后面所有的数依次进行比较,并记录下最小的数的下标
			for (int j = i + 1; j < arr.length; j++) {
				// 如果后面比较的数比记录的最小的数小。
				if (arr[minIndex] > arr[j]) {
					// 记录下最小的那个数的下标
					minIndex = j;
				}
			}
			// 如果最小的数和当前遍历数的下标不一致,说明下标为minIndex的数比当前遍历的数更小。
			if (i != minIndex) {
				int temp = arr[i];
				arr[i] = arr[minIndex];
				arr[minIndex] = temp;
			}
		}
	}

}

P25-3.7排序算法之归并排序

package demo4;

import java.util.Arrays;

public class MergeSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 1, 3, 5, 2, 4, 6, 8, 10 };//【3 1】
		System.out.println(Arrays.toString(arr));
		mergeSort(arr, 0, arr.length - 1);//【0 0 1】
		System.out.println(Arrays.toString(arr));
	}

	// 归并排序
	public static void mergeSort(int[] arr, int low, int high) {
		int middle = (high + low) / 2;
		if (low < high) {
			// 处理左边
			mergeSort(arr, low, middle);
			// 处理右边
			mergeSort(arr, middle + 1, high);
			// 归并
			merge(arr, low, middle, high);
		}
	}

	public static void merge(int[] arr, int low, int middle, int high) {
		// 用于存储归并后的临时数组
		int[] temp = new int[high - low + 1];
		// 记录第一个数组中需要遍历的下标
		int i = low;
		// 记录第二个数组中需要遍历的下标
		int j = middle + 1;
		// 用于记录在临时数组中存放的下标
		int index = 0;
		// 遍历两个数组取出小的数字,放入临时数组中
		while (i <= middle && j <= high) {
			// 第一个数组的数据更小
			if (arr[i] <= arr[j]) {
				// 把小的数据放入临时数组中
				temp[index] = arr[i];
				// 让下标向后移一位;
				i++;
			} else {
				temp[index] = arr[j];
				j++;
			}
			index++;
		}
		// 处理多余的数据
		while (j <= high) {
			temp[index] = arr[j];
			j++;
			index++;
		}
		while (i <= middle) {
			temp[index] = arr[i];
			i++;
			index++;
		}
		// 把临时数组中的数据重新存入原数组
		for (int k = 0; k < temp.length; k++) {
			arr[k + low] = temp[k];
		}
	}

}

P26-3.8排序算法之基数排序

大小都有,数字位数不一样!

排序次数,取决于,数组中最大数字的位数!

先找出数组中最大的数字【int max = Integer.MIN_VALUE;】,

将数字转为字符串---计算位数【int maxLength = (max + "").length();】===》确定循环次数。

第1次,按照个位进行排序!

第2次,按照十位进行排序!

第3次,按照十位进行排序!

余数:0~9   ==>   最多需要10个数组

package demo4;

import java.util.Arrays;

public class RadixSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 23, 6, 189, 45, 9, 287, 56, 1, 798, 34, 65, 652, 5 };
		radixSort(arr);
		System.out.println(Arrays.toString(arr));
	}

	public static void radixSort(int[] arr) {
		// 存最数组中最大的数字
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] > max) {
				max = arr[i];
			}
		}
		// 计算最大数字是几位数
		int maxLength = (max + "").length();
		// 用于临时存储数据的二维数组
		int[][] temp = new int[10][arr.length];// arr.length 避免 空指针异常
		// 用于记录在temp中相应的数组中存放的数字的数量
		int[] counts = new int[10];
		// 根据最大长度的数决定比较的次数
		for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
			// 把每一个数字分别计算余数
			for (int j = 0; j < arr.length; j++) {
				// 计算余数
				int ys = arr[j] / n % 10;
				// 把当前遍历的数据放入指定的数组中
				temp[ys][counts[ys]] = arr[j];
				// 记录数量
				counts[ys]++;
			}
			// 记录取的元素需要放的位置
			int index = 0;
			// 把数字取出来
			for (int k = 0; k < counts.length; k++) {
				// 记录数量的数组中当前余数记录的数量不为0
				if (counts[k] != 0) {
					// 循环取出元素
					for (int l = 0; l < counts[k]; l++) {
						// 取出元素
						arr[index] = temp[k][l];
						// 记录下一个位置
						index++;
					}
					// 把数量置为0
					counts[k] = 0;
				}
			}
		}
	}

}

P27-3.9基数排序之队列实现

先放进去的先取;后放进去的后取。先进先出!!!队列!!!

package demo4;

import java.util.Arrays;

import demo2.MyQueue;

public class RadixQueueSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 23, 6, 189, 45, 9, 287, 56, 1, 798, 34, 65, 652, 5 };
		radixSort(arr);
		System.out.println(Arrays.toString(arr));
	}

	public static void radixSort(int[] arr) {
		// 存最数组中最大的数字
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] > max) {
				max = arr[i];
			}
		}
		// 计算最大数字是几位数
		int maxLength = (max + "").length();
		// 用于临时存储数据的队列的数组
		MyQueue[] temp = new MyQueue[10];
		// 为队列数组赋值
		for (int i = 0; i < temp.length; i++) {
			temp[i] = new MyQueue();
		}
		// 根据最大长度的数决定比较的次数
		for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
			// 把每一个数字分别计算余数
			for (int j = 0; j < arr.length; j++) {
				// 计算余数
				int ys = arr[j] / n % 10;
				// 把当前遍历的数据放入指定的队列中
				temp[ys].add(arr[j]);
			}
			// 记录取的元素需要放的位置
			int index = 0;
			// 把所有队列中的数字取出来
			for (int k = 0; k < temp.length; k++) {
				// 循环取出元素
				while (!temp[k].isEmpty()) {
					// 取出元素
					arr[index] = temp[k].poll();
					// 记录下一个位置
					index++;
				}
			}
		}
	}

}

多谢观看~~~

猜你喜欢

转载自blog.csdn.net/weixin_44949135/article/details/106784224