数据结构和算法:算法部分
一、算法概述
算法的五个特征
① 有穷性:对于任意一组合法输入值,在执行有穷步骤之后一定能结束,即:算法中的每个步骤都能在有限时间内完成。
② 确定性:在每种情况下所应执行的操作,在算法中都有确切的规定,使算法的执行者或阅读者都能明确其含义及如何执行。并且在任何条件下,算法都只有一条执行路径。
③ 可行性:算法中的所有操作都必须足够基本,都可以通过已经实现的基本操作运算有限次实现之。
④ 有输入:作为算法加工对象的量值,通常体现在算法当中的一组变量。有些输入量需要在算法执行的过程中输入,而有的算法表面上可以没有输入,实际上已被嵌入算法之中。
⑤ 有输出:它是一组与“输入”有确定关系的量值,是算法进行信息加工后得到的结果,这种确定关系即为算法功能。
二、递归思想
递归,就是在运行的过程中调用自己。
递归必须要有三个要素:
(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 排序算法性能对比