数据结构与算法就是预估程序在大量的数据集上运行时需要的时间成本和空间成本!
数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。
选择适当的数据结构可以提高计算机程序的运行效率(时间复杂度)和存储效率(空间复杂度)。
数据结构两大类:线性数据结构和非线性数据结构
一维数组(Array),链表(LinkedList),栈(Stack),队列(Queue),串
String [],int [],ArrayList,Vector,CopyOnWriteArrayList
等。push
),取出元素叫出栈(pop
)。char[]
来进行储存。KMP算法:Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP 算法”,是一个解决模式串在文本串是否出现过,如果出现过,最早出现的位置的经典算法。
KMP算法核心思想:是充分利用上次不匹配时的计算结果,避免"一切重新开始"的计算工作。
关键点就是:在字符串比对的时候,主串的比较位置不需要回退的问题。
二维数组,多维数组,树(Tree),散列表(Hash),图(Graph)
String[][],int[][]
等HashMap
里面的TreeNode就用到了红黑树算法。而B+树在数据库的索引原理里面有典型的应用。树的三种遍历方式
自由树/普通树,二叉树,完全二叉树,满二叉树,二分搜索树,红黑树,B树,B+树
堆(heap)
是完全二叉树,通常用数组实现。散列表(Hash):Hash叫散列或哈希,就是把任意长度的输入(又叫做预映射),变换成固定长度的输出,该输出就是散列值。一般通过Hash算法实现。所谓的Hash算法都是散列算法,把任意长度的输入,变换成固定长度的输出,该输出就是散列值(如:MD5,SHA1,加解密算法等)。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
hashCode
的方法,如果自己没有重写,默认情况就是native方法通过对象的内存的+对象的值然后通过hash散列算法计算出来个int的数字。不同的对象,不同的值有可能计算出来的hashCode可能是一样的。HashTable,HashMap
。哈希表具有较快(常量级)的查询速度,及相对较快的增删速度,所以很适合在海量数据的环境中使用。一般实现哈希表的方法采用“拉链法”,我们可以理解为“链表的数组”。图(Graph):图形结构的数据元素是多对多的关系。
是由一个或多个确定的元素所构成的整体叫做集合。在Java里面可以去广义的去理解为实现了Collection接口的类都叫集合。
比较
有穷性,确定性,可行性,有输入,有输出。
折半查找又称为“二分查找“,算法复杂度为
nlog2n
。查找的序列首先必须是有序的才能进行折半查找。
折半查找思路
设有序顺序表{a[0], a[1], ......, a[n-1]}
,先求出查找区间中间元素下标 mid,然后将该位置值 a[mid] 与要查找值 key 比较。
key=a[mid]
,则查找成功,返回下标;key<a[mid]
,则要查找元素在mid左侧,缩小查找区间到表前半部分再进行折半查找;key>a[mid]
,则要查找元素在mid右侧,缩小查找区间到表后半部分再进行折半查找。过程示例
代码示例,两种方式(递归和非递归)
public class Test { //非递归 public int binSearch(int a[], int low, int high, int key){ while(low<=high){ int mid=(low+high)/2; if(a[mid]==key) return mid; else if(key<a[mid]) high=mid-1; else low=mid+1; } return -1; } //递归 public int binRecSearch(int a[], int low, int high, int key){ if(low<=high){ int mid=(low+high)/2; if(a[mid]==key) return mid; else if(key<a[mid]) return binRecSearch(a, low,mid-1, key); else return binRecSearch(a,mid+1, high, key); } else return -1; } //测试 public static void main(String[] args){ int[] a = { -36, -3, 5, 16, 24, 30, 78, 84, 345, 1004}; Test test = new Test(); //非递归 int pos1=test.binSearch(a,0,a.length-1,-3); if(pos1!=-1) System.out.println("-3所在的位置下标是 "+pos1); else System.out.println("找不到该数字84!"); //递归 int pos2=test.binRecSearch(a,0,a.length-1,84); if(pos2!=-1) System.out.println("84所在的位置下标是 "+pos2); else System.out.println("找不到该数字84!"); } }
基本思想
冒泡排序(Bubble Sort) 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
代码实现
/** * 冒泡排序:比较相邻的元素。如果第一个比第二个大,就交换他们两个。 */ private static void bubbleSort(int[] arr){ for (int i = 0; i < arr.length; i++) { for (int j = i+1; j < arr.length; j++) { if (arr[i] > arr[j]){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } }
基本思想
快速排序(Quick Sort) 使用分治策略来把一个序列(list)分为两个子序列(sub-lists)。
步骤:
代码实现
/** * 快速排序:从数列中挑出一个元素,称为“基准”,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面 */ private static void quickSort(int[] arr, int start, int end){ //结束左右递归 if (start < end){ int base = arr[start]; //选第一个数为基准指 int temp; //记录临时中间值 int i = start, j = end; //start最左,end最右 do { while ((arr[i] < base) && (i < end)) i++; while ((arr[j] > base) && (j > start)) j--; if (i <= j){ temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; i++; j--; } }while (i <= j); if (start < j) quickSort(arr, start, j); if (end > i) quickSort(arr, i, end); } }
基本思想
是一种简单直观的排序方法,每次寻找序列中的最小值,然后放在最末尾的位置。
代码实现
/** * 选择排序:是一种简单直观的排序方法,每次寻找序列中的最小值,然后放在最末尾的位置。 */ private static void selectSort(int[] arr){ int temp; for (int i = 0; i < arr.length; i++) { int k = i; for (int j = arr.length-1; j > i; j--) { if (arr[j] < arr[k]) k = j; } temp = arr[i]; arr[i] = arr[k]; arr[k] = temp; } }
基本思想
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
代码实现
/** * 插入排序:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。 * 从第一个元素开始,该元素可以认为已经被排序 * 取出下一个元素,在已经排序的元素序列中从后向前扫描 * 如果该元素(已排序)大于新元素,将该元素移到下一位置 * 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置 * 将新元素插入到该位置中 * 重复步骤2 */ private static void insertSort(int[] arr){ int temp, j; for (int i = 1; i < arr.length; i++) { temp = arr[i]; for (j = i; j > 0 && temp < arr[j-1]; j--) arr[j] = arr[j-1]; arr[j] = temp; } }
基本思想
归并排序是典型的分治算法,它不断地将某个数组分为两个部分,分别对左子数组与右子数组进行排序,然后将两个数组合并为新的有序数组。
代码实现
/** * 归并排序:是建立在归并操作上的一种有效的排序算法,归并是指将两个已经排序的序列合并成一个序列的操作 * 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 * 设定两个指针,最初位置分别为两个已经排序序列的起始位置 * 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 * 重复步骤3直到某一指针达到序列尾 * 将另一序列剩下的所有元素直接复制到合并序列尾 */ private static void mergeSort(int[] arr, int left, int right){ int t = 1;// 每组元素个数 int size = right - left + 1; while (t < size) { int s = t;// 本次循环每组元素个数 t = 2 * s; int i = left; while (i + (t - 1) < size) { merge(arr, i, i + (s - 1), i + (t - 1)); i += t; } if (i + (s - 1) < right) merge(arr, i, i + (s - 1), right); } } //归并算法实现 private static void merge(int[] data, int p, int q, int r) { int[] B = new int[data.length]; int s = p; int t = q + 1; int k = p; while (s <= q && t <= r) { if (data[s] <= data[t]) { B[k] = data[s]; s++; } else { B[k] = data[t]; t++; } k++; } if (s == q + 1) B[k++] = data[t++]; else B[k++] = data[s++]; for (int i = p; i <= r; i++) data[i] = B[i]; }
package com.mizhu; import java.util.Arrays; public class NumberSort { //调用 public static void main(String[] args) { int[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 1, 0, 8}; System.out.println("排序前---"); System.out.println(Arrays.toString(arr)); // bubbleSort(arr); // quickSort(arr,0, arr.length-1); // selectSort(arr); // insertSort(arr); // mergeSort(arr,0, arr.length-1); System.out.println("排序后---"); System.out.println(Arrays.toString(arr)); } }
觉得有用记得支持一下!!!