![](https://img-blog.csdnimg.cn/20201014180756928.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
算法与数据结构
只要是一些常用的算法
weixin_45801539
这个作者很懒,什么都没留下…
展开
-
深入解读HashMap
HashMap集合简介HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对。HashMap的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突(两个对象调用的hashCode方法计算的哈希码值—致导致计算的数组索引值相同)而存在的(“拉链法"解决冲突)JDK1.8以后在解决哈希冲突原创 2020-12-25 09:27:09 · 215 阅读 · 0 评论 -
红黑树(1)
红黑树的性质:性质1:每个节点要么是黑色,要么是红色;性质2:根节点是黑色。性质3:每个叶子节点(NIL)是黑色(虚拟存在的)。性质4:每个红色结点的两个子结点一定都是黑色。性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点,俗陈:黑高!从性质5又可以推出:性质5.1:如果一个结点存在黑子结点,那么该结点肯定有两个子结点红黑树并不是一个完美平衡二叉查找树,从图1可以看到,根结点P的左子树显然比右子树高,但左子树和右子树的黑结点的层数是相等的,也即任意一个结点到到每个叶子结原创 2020-11-17 16:11:51 · 88 阅读 · 0 评论 -
优先队列
优先队列概述普通的队列是一种先进先出(FIFO)的数据结构,元素在队列尾追加,而从队列头删除。在某些情况下,我们可能需要找出队列中的最大值或者最小值,例如使用一个队列保存计算机的任务,一般情况下计算机的任务都是有优先级的,我们需要在这些计算机的任务中找出优先级最高的任务先执行,执行完毕后就需要把这个任务从队列中移除。普通的队列要完成这样的功能,需要每次遍历队列中的所有元素,比较并找出最大值,效率不是很高,这个时候,我们就可以使用一种特殊的队列来完成这种需求,优先队列。优先队列按照其作用不同,可以分为以原创 2020-11-06 10:08:07 · 130 阅读 · 0 评论 -
排序算法:堆排序
堆排序基本介绍1)堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。2)堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆,注意:没有要求结点的左孩子的值和右孩子的值的大小关系。3)每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。大顶堆示意图:按层进行编号有数组:[50,45,40,20,25,35,30,10,15]从上图可以得到大顶堆的特点:arr[i] &原创 2020-11-03 10:36:10 · 273 阅读 · 0 评论 -
线索化二叉树以及遍历线索化二叉树
问题的提出线索化二叉树的介绍原创 2020-11-02 16:27:30 · 109 阅读 · 0 评论 -
顺序存储二叉树
顺序存储二叉树介绍顺序存储二叉树的特点:1)顺序二叉树通常只考虑完全二叉树2)第n个元素的左子节点为2n+13)第n个元素的右子节点为2n+24)第n个元素的父节点为(n-1)/2(这里是按计算机的整数除法)5) n:表示二叉树中的第几个元素(按0开始编号)代码实现以上面的数组为例,要求按二叉树的排序方式进行遍历。首先创建一个ArrBinaryTree 类,用来实现顺序存储二叉树的遍历//编写一个ArrayBinaryTree,实现顺序存储二叉树遍历public class ArrB原创 2020-11-02 11:26:25 · 62 阅读 · 0 评论 -
二叉树:删除节点
二叉树-删除节点要求1)如果删除的节点是叶子节点,则删除该节点2)如果删除的节点是非叶子节点,则删除该子树.思路:首先考虑如果树是空树root,如果只有一个root结点,则等价将二叉树置空.1).因为我们的二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除结点,而不能去判断当前这个结点是不是需要删除结点。2)如果当前结点的左子结点不为空,并且左子结点就是要删除结点,就将this.left=null;并且就返回(结束递归删除}3).如果当前结点的右子结点不为空,并且右子结点就是要删除结原创 2020-09-09 10:11:30 · 1017 阅读 · 2 评论 -
二叉树:前序中序后序遍历
前序遍历:先输出父节点,再遍历左子树和右子树。中序遍历:先遍历左子树,再输出父节点,再遍历右子树。后序遍历:先遍历左子树,再遍历右子树,最后输出父节点。代码实现1.首先创建结点以及方法:public class Node { private int no; private String name; private Node left;//默认null private Node right;//默认null public Node(int no, St...原创 2020-09-08 17:32:54 · 103 阅读 · 0 评论 -
查找算法:斐波那契
斐波那契(黄金分割法): 黄金分割点指:把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比。斐波那契查找原理 与二分法和插值查找算法相似,仅仅只是改变了中间结点(mid)的位置。在此方法中,mid是位于黄金分割点附近,即mid = low + F(K - 1)- 1。 对F(K - 1)- 1的理解: 1)由斐波那契数列F[K]=F[k-1]+F[k-2]的性质,可以得到原创 2020-09-07 11:29:16 · 131 阅读 · 0 评论 -
查找算法:插值查找
插值查找原理:其中key就是我们要查找的数,相当与在二分法中讲到的findVal。(插值查找算法也要求数组是有序的)代码实现public class InsertSearch { public static void main(String[] args) { int [] arr = new int [100]; for(int i = 0;i < 100;i++){ arr[i] = i + 1; }原创 2020-09-07 09:56:12 · 121 阅读 · 0 评论 -
查找算法:二分法
二分法的思想 (1)确定该区间的中间位置K (2)将查找的值T与array[k]比较。若相等,查找成功返回此位置;否则确定新的查找区域,继续二分查找。区域确定如下:array[k]>T 由数组的有序性可知array[k,k+1,……,high]>T;故新的区间为array[low,……,K-1]b.array[k]<T 类似上面查找区间为array[k+1,……,high]。每一次查找与中间值比较,可以确定是否查找成功,不成功当前查找区间将缩小一半,递归查找即可。时间复杂度为:O(原创 2020-09-04 16:09:26 · 127 阅读 · 0 评论 -
查找算法:线性(顺序)查找算法
线性查找又称顺序查找,是一种最简单的查找方法,它的基本思想是从第一个记录开始,逐个比较记录的关键字,直到和给定的K值相等,则查找成功;若比较结果与文件中n个记录的关键字都不等,则查找失败。代码实现:public class SeqSearch { public static void main(String[] args) { int[] arr = {1,9,5,2,3,-7}; int index = seqSearch(arr,3); if(原创 2020-09-04 11:06:35 · 202 阅读 · 0 评论 -
排序算法基础:基数排序
基数排序(桶排序) 1)基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”(数组)中,达到排序的作用。 2)基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法。 3)基数排序(Radix Sort)是桶排序的扩展。 4)基数排序是1887年赫尔曼·何乐礼发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每原创 2020-09-04 10:20:50 · 178 阅读 · 0 评论 -
排序算法基础:归并排序
**归并排序(MERGE-SORT)**是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。归并排序动态示意图:下面以6,5,3,1,8,7,2,4演示:总体的步骤图:合并步骤图:代码实现:import java.util.Arrays;public class MergetSort { p原创 2020-09-03 16:15:26 · 111 阅读 · 0 评论 -
排序算法基础:快速排序
快速排序(Quicksort) 是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。快速排序算法描述:快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下: 从数列中挑出一个元素,称为 “基准”(pivot); 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比原创 2020-09-03 11:45:01 · 99 阅读 · 0 评论 -
排序算法基础:希尔排序
希尔排序法基本思想 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止希尔排序示意图:希尔排序的动态示意图:代码实现1.交换式(效率低,较好理解)import java.util.Arrays;public class ShellSort { public static void main(String[] args) { int [] arr =原创 2020-09-03 10:21:19 · 82 阅读 · 0 评论 -
排序算法基础:插入排序
插入排序法:插入式排序属于内部排序法,是对于欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的。插入排序(Insertion Sorting)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。插入排序图解...原创 2020-09-03 09:18:19 · 88 阅读 · 0 评论 -
排序算法基础:选择排序
选择排序思想:选择排序(select sorting) 也是一种简单的排序方法。它的基本思想是:第一次从arr[0]^~ arr[n-1]中选取最小值,与arr[0]交换, 第二次从arr[1]* arr[n-1]中选取最小值,与arr[1]交换, 第三次从arr[2]’ arr[n-1]中选取最小值,与arr[2]交换, .,第i次从arr[i-1]^ arr[n-1]中选取最小值,与arr[i-1]交换,.,第n-1次从arr[n-2]^ arr[n-1]中选取最小值,与arr[n-2]交换,总共通过原创 2020-08-14 11:18:58 · 64 阅读 · 0 评论 -
排序算法基础:冒泡排序
冒泡排序(Bubble Sorting) 的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始) , 依次比较相邻元素的值,若发现逆序则交换,使值较大中的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。(优化思想)因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较。冒泡排序图解:代码实现:...原创 2020-08-14 10:19:34 · 155 阅读 · 0 评论 -
排序算法基础:时间复杂度与空间复杂度
排序也被称为排序算法,排序是将一组数据,依照指定的顺序进行排列的过程。排序的分类:内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。2)外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。常见的排序算法分类图示:算法的时间复杂度度量一个程序执行时间的两种方法1)事后统计的方法这种方法可行,但是有两个问题:一是要想对设计的算法的运行性能进行评测,需要实际运行该程序;二是所得时间的统计量依赖于计算机的硬件、软件等环境因素,这种方式,要在同一台计算机的相同状原创 2020-08-14 09:12:22 · 255 阅读 · 0 评论 -
前缀、中缀、后缀表达式(逆波兰表达式)
前缀表达式(波兰表达式)1)前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前。2) 举例说明: (3+4)*5-6对应的前缀表达式就是- * +3 4 5 6。前缀表达式的计算机求值从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈项元素和次项元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果.例如: (3+4)*5-6对应的前缀表达式就是- * +3456,针对前缀表达式求值步骤如下:1)从右原创 2020-08-13 15:01:47 · 275 阅读 · 0 评论 -
栈实现综合计算器(中缀)
思路分析:对于一个表达式,有数字,有符号,因此我们需要创建两个栈。一个数栈:用于存放数字;一个符号栈:用于存放符号。1.通过一个index值(索引),来遍历我们的表达式。2.如果我们发现是一个数字,就直接入数栈。3.如果发现扫描到是一个符号,就分如下情况: 3.1如果发现当前的符号栈为空,就直接入栈 3.2如果符号栈有操作符,就进行比较如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop出两个数,在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符原创 2020-08-13 14:03:01 · 60 阅读 · 0 评论 -
栈的分析和用数组模拟的代码实现
栈的介绍:1)栈的英文为(stack)2)栈是一个先入后出(FILO-First In Last Out)的有序列表。3)栈(stack)是 限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一 端,称为栈底(Bottom)。4)根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除。5)入栈(pop)和出栈(push)的图解:栈原创 2020-08-12 11:00:38 · 83 阅读 · 0 评论 -
环形链表和约瑟夫(约瑟夫环)问题
在开始之前先简单介绍一下约瑟夫问题:Josephu问题为:设编号为1,2, …n的n个人围坐一圈,约定编号为k (1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始损数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。单向环形链表图示:用环形单链表解决约瑟夫问题的思路:1.先创建第一个节点,让first指向该节点,并形成环形。2.后面当我们每创建一个新的节点时,就把该节点,加入到已有的环形链表中即可。遍历环形链表的思路:1.原创 2020-08-07 19:15:54 · 154 阅读 · 0 评论 -
双链表创建及代码实现对其的操作
在上一次了解了单链表的代码实现,以及对单链表操作。可以发现单链表具有以下的缺点:1)单向链表,查找的方向只能是一个方向,从头开始,而双向链表可以向前或者向后查找。2) 单向链表不能自我删除,需要靠辅助节点,而双向链表,则可以自我删除,所以前面我们单链表删除节点时,总是找到temp,temp是待删除节点的前一个节点来删除的。双链表图示:双向链表的遍历,添加,修改,删除的操作思路分析:1)遍历:和单链表一样,只是可以向前,也可以向后查找。2)添加(默认添加到双向链表的最后。) 步骤:先找到双链原创 2020-08-06 15:44:09 · 121 阅读 · 0 评论 -
单链表创建及代码实现对单链表的操作
链表:链表是一个有序的列表;是以节点的方式存储的,是链式存储;其中每一个节点包含data域,next域,next域指向下一个节点;链表的各个节点不一定是连续存放的;链表分带有头节点的链表和没有头节点的链表,根据实际需求确定。head节点:不存放具体的数据;作用就是表示单链表头。下面的代码分别对单链表的操作。大部分代码一致,只是在前面代码上增加了新的操作。1. 在单链表的末尾添加元素的代码实现:package cn.xinan.link;public class SingleLinkedList原创 2020-07-30 09:27:44 · 714 阅读 · 0 评论 -
Java代码数组模拟队列
队列介绍队列是一个有序列表, 可以用数组或是链表来实现。队列遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出。队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中maxSize是该队列的最大容量。因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front及rear分别记I录队列前后端的下标,front 会随着数据输出而改变,而rear则是随着数据输入而改变,如图所示:代码实现如下:import java.util.Scanner;原创 2020-07-22 20:54:52 · 64 阅读 · 0 评论 -
稀疏数组
1.定义:稀疏数组可以看做是普通数组的压缩,但是这里说的普通数组是值无效数据量远大于有效数据量的数组。比如:它的稀疏数组形式为:其各行数字的意义如下:第一行 11 、11、 2分别指有11行 11列 有2个少数不同的数。第二行分别指的指 在第2行第3列有一个不为0的数1;第三行表示在第3行第5列有一个不为0的数2。2.存储原数组中存在大量的无效数据,占据了大量的存储空间,真正有用的数据却少之又少;压缩存储可以节省存储空间以避免资源的不必要的浪费,在数据序列化到磁盘时,压缩存储可以提高IO效原创 2020-07-20 21:00:00 · 154 阅读 · 2 评论