源码下载地址:https://download.csdn.net/download/geduo_83/10913510
初级:Java 数据结构和算法初级:数组、集合和哈希表
中级章:Java 数据结构与算法中级章:栈、队列和链表
进阶篇:Java数据结构与算法进阶篇的树和图
理论:Java数组、集合、哈希表常用算法简析
理论:Java栈、队列、链表常用算法简析
理论:Java树和图的常用算法简析
一、前言
2. 数组
2.1 概念
2.2 特点
2.3 存储结构
2.4 使用场景
2.5 相关算法
3. 收藏
3.1 概念
3.2 特点
3.3 适用场景
3.4 相关算法
3.5 性能分析
4. 哈希表
4.1 概念
4.2 哈希算法
4.3 哈希冲突
4.4 存储结构
4.5 特点
4.6 适用场景
4.7 性能分析
5. 总结
****1.前言****
之前从来没有写过关于数据结构的文章,所以今天我们就在这篇文章中介绍一下最基本、最简单的数据结构。
数组作为数据结构中最基本的存储方式,是我们学习所有数据结构和算法的基石。大多数数据结构都可以使用数组来实现。接下来我们将介绍数组的概念、存储结构、特点以及使用场景。
集合是数组的升级版本。在这篇文章中,我们将介绍集合的概念、特点、实现以及适用场景。
哈希表,也叫散列表,很多语言都是在数组的基础上实现的。当然,哈希表还有其他的实现形式。在这篇文章中,我们将介绍哈希表的基本概念、特点以及实现方法。
****2.大批****
****2.1 概念****
数组是内存中元素的有序序列
****2.2 特点****
定长、顺序访问、快速索引、慢速插入和删除
****2.3 存储结构****
[图片上传失败.(image-f51670-1553424312385)]
image.gif[图片上传失败.(image-1f1cb-1553424312387)]
图片.gif
****2.4 使用场景****
数组其实是一种非常简单的数据结构,使用起来也比较简单。它是所有其他数据结构的基础,所以只有掌握了数组才能学好其他数据结构和算法。
什么时候使用数组?从数据的特性来看,我们可以认为数据的长度是固定的,所以在长度不会改变的业务中使用数组比较合适。
如果我们使用app开发中非常常见的菜单按钮,它们的数量一般是固定的,不会改变。如下图所示,界面有首页、报表、消息、我的。我们可以使用数组来存储它们。
[图片上传失败.(image-c4b201-1553424312385)]
image.gif[图片上传失败.(image-fa42a-1553424312387)]
图片.gif
****2.5相关算法****
****2.5.1 冒泡排序****
排序是通过比较两个相邻的数字来执行的。有两个循环。第一个循环控制循环的轮数。第二个循环控制每轮的循环次数。第一个循环确定最后一个元素,第二轮循环确定倒数第二个元素。如此下去,直到确定第一个元素,循环排序完成。
需要注意的是,第一次循环的结束条件是i len-1;第二次循环的结束条件是j len - i - 1;
封装A数组.A001冒泡排序;
/**
* 描述:冒泡排序
* 作者: 门中之龙
*日期: 2018/11/21
* 版本: V1.0.0
*更新:
*/
公共类主算法{
公共静态无效主(字符串[] arg){
int[] arr={1, 3, 10, 1, 34, 5, 21};
排序冒泡(arr);
整数i=0;
while (我arr.长度) {
System.out.println(arr[i]);
我++;
}
}
//冒泡排序:两个循环,通过两两比较来排序
私有静态void sortBubbling(int[] arr) {
//第一轮决定最后一个,第二轮决定倒数第二个.
for (int i=0; i arr.length - 1; i++) {
for (int j=0; j arr.length - i - 1; j++) {
//比较两对就像鱼吐泡泡.
if (arr[j] arr[j + 1]) {
int temp=arr[j + 1];
arr[j + 1]=arr[j];
arr[j]=温度;
}
}
}
}
}image.gif****2.5.2 选择排序****
第一步是将第一个元素与其余元素进行比较并确定第一个元素。第二步,将第二元素与其余元素进行比较,确定第二元素。如此继续下去,直到确定了最后一个元素时,循环排序完成。和冒泡排序一样,也是通过两个循环完成的。第一个循环控制循环的轮数,第二个循环控制每轮的循环次数。
需要注意的是,第一个循环的结束条件是i len-1,这和冒泡排序是一样的。第二次循环的起始条件为j=i + 1;结束条件是j len。
通过分析,不难得出,无论是冒泡排序还是选择排序,控制轮次的第一个循环的结束条件都是一样的,len - 1;控制每轮循环次数的第二个条件是相反,冒泡排序控制结束条件j len - i - 1,而选择排序控制开始条件j=i + i。
这是我们哲学中的一个矛盾,而冒泡和选择是我们矛盾的两个方面。
封装A数组.A002选择排序;
/**
* 描述:选择排序
* 作者: 门中之龙
*日期: 2018/11/21
* 版本: V1.0.0
*更新:
*/
公共类主算法{
公共静态无效主(字符串[] arg){
int[] arr={1, 3, 10, 1, 34, 5, 21};
排序更改(arr);
整数i=0;
while (我arr.长度) {
System.out.println(arr[i]);
我++;
}
}
//选择排序,选择第一个元素并与剩余的n-1进行比较
私有静态void sortChange(int[] arr) {
//第一轮确定第一个元素,第二轮确定第二个元素
for (int i=0; i arr.length; i++) {
for (int j=i + 1; j arr.length; j++) {
//选择第i个元素并与其余元素进行比较
if (arr[i] arr[j]) {
int temp=arr[i];
arr[i]=arr[j];
arr[j]=温度;
}
}
}
}
}image.gif****2.5.3 桶排序****
桶排序的核心思想是用源数组的值作为新数组的下标来查找新元素,然后给该元素加1。通过遍历源数组,将新数组加1。经过一轮循环后,排序就确定了。然后遍历新数组。只要找到值大于0的元素,就会打印它的下标。打印出来的值就是我们想要的。期望的结果。
我们需要注意的是,桶排序有一个前提,就是你必须知道源数组中的最大元素,因为只有知道了最大元素,才能确定新数组的长度。
桶排序效率很高,但是如果源数组的值不均匀,必然会造成空间的浪费。桶排序就是一个以空间换时间的典型例子。
封装A数组.A003桶排序;
/**
* 描述: 桶排序
* 作者: 门中之龙
*日期: 2018/11/21
* 版本: V1.0.0
*更新:
*/
公共类主算法{
公共静态无效主(字符串[] arg){
int[] arr={1, 3, 10, 1, 34, 5, 21};
排序桶(arr);
//int i=0;
//while (i arr.length) {
//System.out.println(arr[i]);
//i++;
//}
}
//桶排序,声明一个以最大元素+1为长度的数组,遍历原数组,对桶数组进行计数
私有静态无效sortBucket(int[] arr) {
int[] arr1=新int[34 + 1];
for (int i=0; i arr.length; i++) {
arr1[arr[i]]++;
}
for (int i=0; i arr1.length; i++) {
int 计数=arr1[i];
而(计数0){
System.out.println(i);
数数- ;
}
}
}
}image.gif****2.5.4 数组中是否存在重复元素****
说到重复元素,我们自然会想到数组和集合。两种数据结构都允许重复数据,而哈希表不允许重复数据。
我们思考如果我们迭代数组中的元素并将它们存储在哈希表中会发生什么?有人会说,没必要重复。是的,没有错,但更重要的是,当我们将数组的元素存入哈希表时,我们添加了一个判断来判断该元素是否存在于哈希表中。这不是结束了吗?如果哈希表中没有任何内容,则直接存储。如果有则直接返回。就是这么简单。
这个技巧需要我们对哈希表有很好的理解。事实上,集合和哈希表都有contains 方法。
package A数组.A004数组是否存在重复元素;
导入java.util.HashSet;
/**
* 说明: 数组是否有重复元素
* 作者: 门中之龙
*日期: 2018/11/21
* 版本: V1.0.0
*更新:
*/
公共类主算法{
公共静态无效主(字符串[] arg){
int[] arr={11, 3, 10, 11, 34, 5, 21};
System.out.println(checkRepeat(arr));
}
//判断数组中是否有重复元素
私有静态布尔checkRepeat(int[] arr) {
//1.声明一个哈希表
//2. 遍历这个数组
//3.按顺序判断遍历到的元素。如果哈希表中没有元素,则将其添加到哈希表中。如果有则直接退出。
HashSethashSet=new HashSet();
for (int i=0; i arr.length; i++) {
if (hashSet.contains(arr[i])) {
返回真;
} 别的{
hashSet.add(arr[i]);
}
}
返回假;
}
}image.gif****2.5.5 删除数组中的重复元素****
通过我们上面判断数组是否存在重复元素的分析,解决这个问题非常简单。只需使用哈希表即可。
还有其他解决方案吗?有没有一种方案可以直接实现而不需要使用其他数据结构呢?是的,其实解决方案的中心思想就是选择排序有点像取出当前元素并与其他剩余元素进行比较。如果有相等的元素,则所有后续元素将向前移动一位。移动完成后,会计算源数组的长度。压缩过程减1,压缩完成后从头开始判断循环。
这种方法要注意两点。首先,只要相等,后面的所有元素都会前移。那么,移动完成后,源数组的长度就会减1进行压缩。压缩完成后,循环又开始。
封装A数组。A005删除数组中重复的元素;
导入java.util.Arrays;
/**
* 描述: 从数组中删除重复元素
* 作者: 门中之龙
*日期: 2018/11/21
* 版本: V1.0.0
*更新:
*/
公共类主要算法{
公共静态无效主(字符串[] arg){
int[] arr={1, 3, 10, 1, 34, 5, 21};
arr=删除重复(arr);
整数i=0;
while (我arr.长度) {
System.out.println(arr[i]);
我++;
}
}
//查找数组中是否存在重复元素,如果存在则删除重复元素
私有静态int[] removeRepeat(int[] arr) {
//取出第一个元素并与其余元素进行比较
//一旦找到相等,则所有后续元素将向前移动1,并且数组将被移动。
Loop: for (int i=0; i arr.length; i++) {
for (int k=i + 1; k arr.length; k++) {
//如果相等,则后面的元素同意继续前进
if (arr[i]==arr[k]) {
int 头=k;
while (头部长度- 1) {
arr[头]=arr[头+ 1];
头++;
}
//压缩数组
arr=Arrays.copyOf(arr, arr.length - 1);
我=0;
//压缩完成,再次开始执行
继续循环;
}
}
}
返回arr;
}
}image.gif****2.5.6 两个数字之和****
说到两个数字的和,那么你会想到数组中的任意两个元素都会触及和,并将其与我们的目标数字进行比较。如果相等,则返回两个元素的下标,这样就解决了问题。
任何两个元素都必须碰撞。这时候我们就想到了选择排序。通过这个算法,我们可以实现二乘二的碰撞。两个循环一个判断就可以解决问题。
还有另一种算法。首先,我们可以创建一个新的数据对象。该对象有两个字段,一个存储下标,一个存储元素的值。然后我们通过源数组创建一个以新数据对象为元素的数组并对数组进行排序,然后声明两个指针,一个头指针和一个尾指针。这两个指针分别从数组的头部和尾部向前和向后移动。总结每一步并与目标数字进行比较。如果小于目标数,则头指针向前移动,然后进行求和比较。如果大于目标数,则尾指针向后移动,然后进行求和比较。直到相等,返回两个对象的下标,问题解决。
两种算法都有各自的优点和缺点。方案一当然是最简单的,代码量也最少。方案2让我们感受到了指针在计算中的神奇作用。虽然代码量有点大,但是思路还是很清晰的。
包A数组.A006 两个数之和;
导入java.util.Arrays;
/**
* 描述:
* 作者: 门中之龙
*日期: 2018/11/21
* 版本: V1.0.0
*更新:
*/
公共类主算法{
公共静态无效主(字符串[] args){
int[] arr={1, 23, 12, 2, 11, 22};
int[] res=get(arr, 33);
System.out.println(Arrays.toString(res));
}
静态类Data 实现Comparable{
整数索引;
整数数据;
公共数据(int索引,int数据){
this.index=索引;
this.data=数据;
}
@覆盖
公共int 比较(数据o){
返回数据-o.data;
}
@覆盖
公共字符串toString() {
return "数据{" + "索引=" + 索引+ ", 数据=" + 数据+ "}";
}
}
//指定一个目标数,查找两个数之和等于目标数的下标
公共静态int[] get(int[] arr, int sum) {
int[] 结果={0, 0};
//1.首先对原数组进行排序
Data[] arr1=new Data[arr.length];
整数i=0;
while(我arr.length){
arr1[i]=新数据(i,arr[i]);
我++;
}
Arrays.sort(arr1);
System.out.println(Arrays.toString(arr1));
//2.声明两个指针,head和tail
整数头=0;
int tail=arr.length - 1;
而(头尾){
if ((arr1[head].data + arr1[tail].data)==sum) {
结果[0]=arr1[头].index;
结果[1]=arr1[tail].index;
返回结果;
} else if ((arr1[head].data + arr1[tail].data) sum) {
头++;
} 别的{
尾巴- ;
}
}
返回空值;
}
}image.gif****2.5.7 求从左上到右下的路径数****
这道题的大致思路是这样的。已知给定一个m*n的二维数组,以第一个元素为起点,最后一个元素为终点。然后起点开始移动,而且只能向右移动。向下移动直至到达终点,一共有多少条路?
很多人看到这个算法题都会一头雾水。实在是没办法解决。其背后的逻辑关系是什么?将使用什么数据结构?使用什么样的循环?使用什么样的判断?
其实具体的思路是这样的。声明一个m*n的二维数组,初始化赋值为0,然后给数组第一行赋值为1,然后给数组第一列赋值为1,最后一步赋值数组的值。中剩余的所有其他元素都被分配一个值。其他元素的值是其正上方元素的值与紧邻左侧元素的值之和。赋值完成后,最后一个元素arr[m-1][n-1]的值为我们要计算的路径数,令人困惑。为什么?为什么这个赋值是我们想要计算结果的路径数呢?其实这就是算法中动态规划的问题。
我们将值1 分配给第一行和第一列。为什么?如果只有一行或者只有一列,这两种情况都只有一种方式,所以赋值为1并没有什么问题。这是符合逻辑的,然后我们开始移动。我们每走一步无非就是两个选择,要么向前走,要么向下走,那么有两种方式可以走到当前格子,而这个值就是它正上方的元素和正左边的元素之和,那么同样的原理适用于其他网格的值,最后一个元素arr[m -1][n-1] 的值就是我们要计算的路径数。
这就是动态规划的奥秘,它简单地通过三个循环就解决了我们的问题。
package A array.A007 从左上到右下的路径数;
/**
* 描述: 在m*n 的矩形网格中,机器人只能在最左上方的网格中一次移动一步,并且只能向右和向下移动。目标位置位于最右下角的方块中。总共有多少条路径?
* 作者: 门中之龙
*日期: 2018/11/23
* 版本: V1.0.0
*更新:
*/
公共类主算法{
公共静态无效主(字符串[] args){
int 路径=getPath(3, 3);
System.out.println(路径);
int[][] arr=新int[2][3];
System.out.println("length:"+arr.length);
}
//动态规划问题
公共静态int getPath(int m, int n) {
int[][] arr=新int[m][n];
//将第一行赋值为1
for (int i=0; i n; i++) {
arr[0][i]=1;
}
//将第一列赋值为1
for (int i=0; i m; i++) {
arr[i][0]=1;
}
//给其他单元格赋值
for (int i=1; i m; i++) {
for (int j=1; j n; j++) {
arr[i][j]=arr[i - 1][j] + arr[i][j - 1];
}
}
返回arr[m - 1][n - 1];
}
}image.gif****2.5.8 求从左上到右下的路径的最小值****
这个问题是上面求路径数问题的延伸,求最小路径数。不同的是,它仍然是一个m*n的二维数组,但是这个数组
每个元素都已经赋值了,让你求路径上所有元素的和的最小值,从左上到右下的路径有n多条,但是肯定有一条的和值是最小的。其实这还是一个动态规划的问题。 具体解决思路如下,首先声明一个大小完全相同二维数组,现在要给其赋值,赋值完毕我们要的结果也就出来了,第一个元素的值就是源数组第一个元素的值,第一行其他元素的值就是当前元素的前导元素的值和源数组这个位置元素的值的和,第一列其他元素的值就是他的前导元素的值与源数组这个位置元素的值的和,然后其他元素的值就是当前元素上方元素和左方元素取最小值和源数组这个位置元素的值求和,其他元素得计算方式以此类推,直到赋值完成,而最后一个元素的值就是我们要计算的左上到右下路径的最小值。 通过分析我们不难发现,不管是求路径数,还是求路径的最小值,其背后的核心思想都是动态规划。通过对数组的动态的赋值计算,从而得到我们要计算的结果。 package A数组.A008左上到右下路径中的最小值; /** * Description:<在一个m*n的矩形方格中, 机器人在最左上的格子里,一次只能挪动一步,只能往右往下移动 目标地点在最右下方的方格里,问共有几条路径,求路径中的最小值> * Author: 门心叼龙 * Date: 2018/11/23 * Version: V1.0.2 * Update: */ public class MainAlgorithm { public static void main(String[] args) { int[][] grid = new int[][] {{1, 1, 8}, {3, 1, 4}, {6, 2, 1}}; int minvalue = getMinvalue(grid); System.out.println(minvalue); } private static int getMinvalue(int[][] grid) { int[][] result = new int[grid.length][grid[0].length]; // 给result[0][0]赋值 result[0][0] = grid[0][0]; // 给第一行赋值 for (int i = 1; i< result[0].length; i++) { result[0][i] = result[0][i - 1] + grid[0][i]; } // 给第一列赋值 for (int i = 1; i< result.length; i++) { result[i][0] = result[i - 1][0] + grid[i][0]; } // 给其他元素赋值 for (int i = 1; i< result.length; i++) { for (int j = 1; j< result[0].length; j++) { result[i][j] = Math.min(result[i - 1][j], result[i][j - 1]) + grid[i][j]; } } return result[result.length - 1][result[0].length - 1]; } }image.gif****3. 集合**** ****3.1 概念**** 大家知道数据的致命缺点就是长度固定,如果我们要存储的数据长度不固定,该怎么办?这时候就要用集合了,其实集合也是基于数组实现的,不过它是一个变长数组,想放入多少就可以放入多少。集合就是一个变长数组或者叫做动态数组。 ****3.2 特点**** 1.它的长度是可变的 2.他会浪费一定内存空间 3.数据的拷贝会浪费一定的时间 ****3.3 适用场景**** 集合的适用场景非常多,如果博客的文章列表、评论列表等,只要有列表就有集合的身影。 imageimage.gif ****3.4 常见的算法**** ****3.4.1 自定义实现一个集合**** 集合我们知道他是一个变长数组,只有变长才能源源不断的往里面存放数据,通过集合元素添加流程图我们也能看到,首先需要初始化一个数组,然后在添加元素的时候如果源数组满了就需要扩容了,当然扩容的系数有的是2倍,有的是0.75倍,这由自己定,不管是数组的扩容还是压缩都用到了数组工具类中非常重要的一个方法Arrays.copy(),有了添加的方法,必然少不了删除方法,删除的思路也很简单,就是把要删除的元素之后的元素都往回移动一位,然后再把最后一个元素赋值为0再退出循环就ok了。 现在我们不妨画个流程图方便大家理解集合的工作原理: imageimage.gif 代码实现如下: package B集合.A001自定义实现一个ArrayList; import java.util.Arrays; /** * Description:<自定义实现一个ArrayList> * Author: 门心叼龙 * Date: 2018/11/19 * Version: V1.0.0 * Update: */ public class MyArrayList { private int[] arr; private int initsize = 5; private int size = 0; public MyArrayList() { arr = new int[initsize]; } public int get(int index) { return arr[index]; } public boolean add(int value) { // 说明此时数组已经满了,要扩容了 if (size == arr.length) { System.out.println("数组要扩容了..."); arr = Arrays.copyOf(arr, size * 2); } arr[size++] = value; return true; } public boolean remove(int value) { if (arr.length >0) { loop: for (int i = 0; i< arr.length; i++) { if (arr[i] == value) { int temp = i; while (temp< arr.length - 1) { arr[temp] = arr[temp + 1]; temp++; } arr[--size] = 0; break loop; } } } return true; } public int size() { return size; } }image.gif****3.4.2 删除集合中的偶数**** 很多初学者看到这个问题都觉的太简单了,不就一个循环就解决问题了吗?其实这是有大问题的,问什么?你想了循环开始的时候循环结束的条件就已经确定了,如果你在循环的过程中删除了一个元素,那么数组长度就变短了,而我们循环并没有停止,当循环走到最后的时候势必会造成数组下标越界的空指针异常,怎么办?其实我们通过集合迭代器来做这个删除的工作就可以完美的规避这个问题。因为迭代器不需要下标,也就不存在数组下标越界的问题。 package B集合.A002删除集合中的偶数; import java.util.ArrayList; import java.util.Iterator; /** * Description:<删除集合中的偶数> * Author: 门心叼龙 * Date: 2018/11/21 * Version: V1.0.0 * Update: */ public class MainAlgorithm { public static void main(String[] arg) { ArrayListlist = new ArrayList() { { add(1); add(2); add(3); add(4); } }; removeEvenNumber(list); int i = 0; while (i< list.size()) { System.out.println(list.get(i)); i++; } } // 删除集合中的偶数元素 private static void removeEvenNumber(ArrayListmyArrayList) { Iteratoriterator = myArrayList.iterator(); while (iterator.hasNext()) { Integer next = iterator.next(); if (next % 2 == 0) { iterator.remove(); } } } }image.gif****3.5 性能分析**** 在算法中,每种算法的性能指标一般都有两个,即时间复杂度和空间复杂度。 时间复杂度:它定量的描述了该算法的运行时间。常常用大写的O表示。 空间复杂度:是对一个算法在运行过程中临时占用的存储空间大小的度量。 虽然集合这个变长数组比普通的数组高级一些,但是本质上它还是基于数组实现的,所以它和数组的性能差不多。 对于数组的操作,并不像我们看到的那么直观,计算机需要根据我们具体操作的位置,从头到尾一个一个地寻找到指定的位置,所以我们在数组中增加元素、修改元素、获取元素等操作的时间复杂度都为O(n)。 变长数据也有性能损耗的问题,如果插入的元素发现其中固定的数组的长度不够,则需要建立一个新的更长的数组,还要拷贝元素到新的数组,这都会造成性能损耗。 ****4. 散列表**** ****4.1 概念**** 前面我们讲了数组和集合,他们都有一个共同的特点,他们在内存中的存储顺序是有序的,如果数据量很大我们需要在数组或者集合中查找一个元素,或者在数组或集合的头部添加或者删除一个元素,它的性能就会大大降低。 此时散列表就应运而生了,散列表是一种以空间换时间的数据结构。 让我们想一下,若在手机的通信录中查找一个人,那我们应该不会从第1个人一直的查找下去,因为这样实在是太慢了。我们其实是这样做的:首先看这个人的名字的首字母是什么,比如姓赵,那么我们会点击字母z,列表里以字母z开始的人名都会迅速的查找出来,就很快的查找到我们要查找的那个人。 还有我们在查字典的时候,需要查找一个单词,肯定不会从头翻到尾,而是通过这字的首字母,查找到对应的那一页,这样可以速度的跳到那个字所在的页面。 其实这里就用到了散列表的思想。 散列表又叫哈希表,能通过给定的关键字的值直接访问到具体对应的值的一个数据结构。也就是说,通过关键字映射到一个表中的位置来直接访问记录,以加速访问的速度。 而这个关键字就是我通常所说的key,把对应的记录称为value,所以可以说也是通过这个key访问一个映射表来得到value的值,而这个映射表就是所说的散列表,也叫哈希表。 ****4.2 哈希算法**** 刚才我们说到,通过关键字映射到一个表中的位置来直接访问记录,这个映射到表中的位置就是通过哈希算法来实现的,目前这个哈希算法的实现的方法比较多,主要有以下一种: 1.直接寻址法 2.数字分析法 3.平方取中法 4.随机数法 5.除留取余法 ****4.3 哈希冲突**** 会有这样一种情况,有多个不同的Key通过哈希函数可能会得到相同的地址,这样就会造成对数据的覆盖、丢失。那么解决哈希冲突的处理方式也有很多种,主要有以下几种方法: 1.开放地址法 2.再哈希法 3.链接地址法 ****4.4 存储结构**** 一个好的散列表设计,除了需要选择一个性能较好的哈希函数,还要选择一个好的冲突解决方式。这里我们选择除留取余法作为哈希算法,选择链接地址法作为冲突的处理方式。 imageimage.gif ****4.5 特点**** 散列表有两种用法,一种是key的值和Value的值一样,一般我们称这种数据结构为Set集合;如果Key的值和Value的值不一样,我们称这种情况为Map。 1.增啥改查的速度都很快 2.无序 ****4.6 适用场景**** 1.数据缓存 2.快速查找 ****4.7 性能分析**** 散列表的访问,如果没有碰撞,那么我们完全可以认为对元素的访问的时间复杂度为O(1) 但是实际上不可能没有碰撞,Java中使用链表来解决,而碰撞之后的访问需要遍历链表,所以时间的复杂度将变为O(L),其中L为链表的长度。 ****5. 小结**** 数组,作为数据结构中最为基础的、常用的一个结构。而集合与散列表他们都是在数组的基础上进行稍微高级点的扩展的数据结构,通过对比这三种数据结构,我们更加清楚他们之间的区别和应用场景了,对数组的应用有了更加深入的理解。 源码下载地址:https://download.csdn.net/download/geduo_83/10913510 初级篇:Java数据结构与算法初级篇之数组、集合和散列表 中级篇:Java数据结构与算法中级篇之栈、队列、链表 高级篇:Java数据结构与算法高级篇之树、图 理论篇:Java数组、集合、散列表常见算法浅析 理论篇:Java栈、队列、链表常见算法浅析 理论篇:Java树、图常见算法浅析问题反馈
有任何问题,请在文章下方留言。关于作者var geduo_83 = { nickName : "门心叼龙",【Java基础:数组、集合与散列表入门指南】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
学习数据结构和算法是程序员必备技能
有17位网友表示赞同!
这个 Java 数据结构教程讲得挺全面,介绍了基础概念。
有16位网友表示赞同!
数组、集合和散列表都是计算机编程中常用的数据结构。
有10位网友表示赞同!
想要掌握 Java 编程技巧,理解这些数据结构太重要了~
有6位网友表示赞同!
感觉初学者看这个教程就能快速入门 java 数据结构
有15位网友表示赞同!
刚开始学 Java, 不知道从哪里下手,看了这个教程好像好点!
有16位网友表示赞同!
Java 代码里经常会用数组和集合这类数据结构
有18位网友表示赞同!
散列表的概念我一直不太理解,这里讲解得挺清晰的
有9位网友表示赞同!
想参加 Java 技术面试,这些数据结构要先好好复习一下
有8位网友表示赞同!
这个教程对初学者真的很友好!
有12位网友表示赞同!
希望以后可以学习更高级的数据结构和算法
有19位网友表示赞同!
Java 数据结构应用很广,理解它能让我写出更巧妙的代码
有17位网友表示赞同!
学习数据结构的感觉就像在组装积木,很有成就感~
有20位网友表示赞同!
这个教程讲得通俗易懂,让人容易掌握
有13位网友表示赞同!
数据结构是编程的基础,这个教程是个不错的入门教材
有7位网友表示赞同!
终于找到一本讲解 Java 数据结构的好的书了!
有7位网友表示赞同!
要成为一名合格的程序员,学习数据结构和算法是必不可少的
有7位网友表示赞同!
通过数组、集合和散列表,可以更好地管理和处理数据
有13位网友表示赞同!
这个教程让我对 JAVA 数据结构有了更深入的理解!
有12位网友表示赞同!