数据结构与算法
文章平均质量分 71
总结记录学习数据结构与算法过程中的知识
有裂痕的石头
埋头苦干,未来可期
展开
-
更高效地刷OJ——Java中常用的排序方法,Array.sort(),Arrays.parallelSort(), Collections.sort()
对于几大传统的排序算法我在前面博客中已经介绍过了,如果有想要了解的同学可以去看这篇博客八大排序:冒泡排序,选择排序,插入排序,堆排序,希尔排序,归并排序,计数排序但是我们在刷题过程中如果题目中没有对排序算法做特别要求,排序只是当前题目的一个小过程的话我们大可不必自己实现以便排序算法,因为Java中已经提供了几个对数据做排序的方法。文章目录用Array.sort()进行排序Arrays.parallelSort() 是什么 和 Array.sort()有什么区别用 Collections.sort()进行排原创 2021-09-12 17:47:10 · 855 阅读 · 50 评论 -
模拟实现HashMap
为了方便实现,突出重点,将key指定为String类型,将Value指定位Integer类。在实际中,如果Key的类型为自己的实现类,那么必须重写该类的hashCode()和equals()两个方法,重写hashCode()方法是因为在找key对应的下标时需要调用hashCode()方法,重写equals()方法是因为两个相同对象的哈希值必须相同,程序怎么知道哪两个对象相同,就是通过equals方法。对于还不了解哈希表的同学建议先去看上一篇博客哈希表(HashTable),哈希冲突的避免、解决。下面开原创 2021-09-11 17:38:46 · 230 阅读 · 0 评论 -
哈希表(HashTable),哈希冲突的避免、解决
文章目录什么是哈希表哈希表概念哈希冲突哈希冲突概念解决冲突闭散列闭散列平均查找次数的问题开散列/哈希桶冲突严重时的解决办法避免冲突哈希函数设计常见的哈希函数负载因子调节什么是哈希表先举一个很常见的例子:我们有一个衣柜这是一个杂乱无章的衣柜,里面放了四季的衣服,每当要去找一件合适的衣服去穿的时候,要翻箱倒柜麻烦半天,为了解决这个问题,我们买了四个柜子,规定它们分别存放春夏秋冬四季的衣服:从此之后找衣服就方便了很多,什么季节去哪个衣柜找就能找到合适的衣服,这个例子背后就是哈希表的原理。哈希表概念原创 2021-09-11 12:13:45 · 2362 阅读 · 24 评论 -
Java中的Map
Map的介绍Map和Set一样是一种专门用来进行搜索的数据结构,和Set不同的是Map中存的是Key-Value键值对,什么是键值对呢?举两个例子:统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:这里的key就是单词,value就是出现的次数。词典中每个单词就是key,单词对应的意思是value。Java中的Map是一个接口,该类不同于Set,该类没有继承字Collection。Map中的key不能重复,value可以重复。Map的常用方法:返回值方法原创 2021-09-10 21:46:02 · 244 阅读 · 2 评论 -
Java中的Set
Set可以被认为是一个集合,集合内部是同类型的元素,他们之间没有先后顺序,但是不允许重复!!!Set中常用的方法有以下几个:返回值方法booleanadd( ) 向集合中添加元素无clear( ) 去掉集合中所有的元素booleancontains( ) 判断集合中是否包含某一个元素booleanisEmpty( ) 判断集合是否为空Iteratoriterator( ) 主要用于递归集合,返回一个It原创 2021-09-10 15:32:41 · 7877 阅读 · 16 评论 -
二叉搜索树的思想,以及增删查改的实现
目录搜索树的概念查找操作插入操作删除操作改的操作搜索树的概念二叉搜索树又被称为排序树,它或者是一颗空树,或者是一棵具有以下性质的二叉树:若它的左子树不为空,则左子树上所有节点的值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树下图就是一棵二叉搜索树,可以对应上面性质加深理解:查找操作实现思想:实现代码:// O(树的高度) public boolean find(int key) { Node curren原创 2021-09-07 22:48:38 · 671 阅读 · 21 评论 -
❤️万字总结八大排序:冒泡排序,选择排序,插入排序,堆排序,希尔排序,归并排序,计数排序❤️
目录主要排序算法性能对比冒泡排序选择排序插入排序堆排序希尔排序快速排序Hoare版挖坑版前后指针法归并排序计数排序主要排序算法性能对比冒泡排序各位同学接触最早的排序算法应该就是冒泡排序了,他的过程如下图所示:拿图中升序举例他每次小循环都会从0开始在遍历的过程中将遇到的最大的数像冒泡泡一样一路冒到有序区间,一次大循环让有序区间增加一,大循环执行完毕全部区间就有序了。下面是它的代码:import java.util.Arrays;public class BubbleSort { //升原创 2021-09-06 17:15:49 · 394 阅读 · 21 评论 -
归并排序(Merge Sort)思想,代码实现
归并排序是分治算法一个非常典型的例子,归并排序的思想是将待排序序列递归分为左右两个子序列,递归到子序列只有一个数的时候,停下来,这就是分治算法的分的意思,将问题化简,当子序列只有一个元素的时候是不是可以认为这个序列为有序序列了,然后再将左右有序子序列通过递归合并起来,最终让整个序列有序,这是分治算法治的过程,下面我们通过图片来理解这个过程:通过动图理解就是:线面看代码:public class MergeSort { public static void mergeSort(long[]原创 2021-09-05 22:54:57 · 681 阅读 · 20 评论 -
快速排序思路(前后指针版),代码实现
快速排序的前后指针法相比于Hoare版和挖坑版在思路上有点不同,前后指针版的思路是引入两个指针cur和prev,在开始的时候先规定一个基准值val(一般为最右边或者最左边的那个数据),然后让两个指针指向基准值的下一个数,开始下面循环:若cur指向的内容小于key,则prev先向后移动一位,然后交换prev和cur指向的数,然后cur++;如果cur指向的内容大于val,则cur++。直到cur走完整个序列,此时为了让基准值在中间,只需val和prev交换单次排序就完成了。下面是单次排序的动图:在循环原创 2021-09-04 11:45:08 · 496 阅读 · 4 评论 -
快速排序思路(挖坑版),代码实现
挖坑版是在Hoare版的基础上做了改造,答题思路还是和Hoare版一样。挖坑版partition单次过程:选一个基准值,一般选最左或者最右面,把该基准值存在val变量中,因为值存到了变量里,所以可以视为这个位置能放其他值了。定义一个left和一个right引用,left从序列左向右走,right相反(如果基准值在左边则right先走,如果基准值在右边,left先走)走的过程中,如果right遇到小于val的数,则把个数放在坑中,并在次形成坑位,然后left向右走,如果遇到大于val的数,则将值填入原创 2021-09-03 23:04:31 · 612 阅读 · 10 评论 -
快速排序思路(Hoare版),代码实现
快速排序是一种相对比较快的排序,它的思想为:选取待排序元素序列中的一个元素作为基准值,然后(以升序为例)比基准值小的元素放在基准值左边,比基准值大的元素放在基准值右边,这样的话,原先待排序序列就被分为了左子序列,右子序列,基准值,三个部分,,然后把左子序列看做新的待排序序列进行上述操作,左子序列又被分为新的左右子序列(递归的思想),当左子序列处理完之后再去处理右子序列,最后着呢个待排序序列就有序了。下面是动图演示过程:public static void quickSort(int[] array)原创 2021-09-01 23:18:39 · 287 阅读 · 13 评论 -
希尔排序(Shell Sort)
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。上面的这段叙述来自百度百科,我们可以知道希尔排序是插入排序的改进版,如果插入排序还没有搞清楚的话,建议先去看这篇博客补一补:都是❤️两层循环❤️的冒泡排序,选择排序,插入排序该怎么区分。这里我们也大致在对插入排序做个复习。插入排序将第一个数(也可.原创 2021-08-30 23:41:03 · 539 阅读 · 8 评论 -
堆排序,为什么升序排列要建大堆,降序排列要建小堆
堆排序中用到了建立大小堆和向下调整的内容,对这些内容有些不了解的同学可以去补一补专门写堆的博客,方便更好的理解堆排序数据结构之堆(Heap),堆的相关操作,用堆模拟优先级队列。如果把待排序序列分为未排序区间和有序区间,堆排序大的思想是每次选一个数放到有序区间,没经历一个循环有序区间就会加一,无序区间减一,循环结束序列也就有序了,像这样:可以发现堆排序的思路和选择排序很像,没错,思路确实一样,只不过选择排序每次要遍历无序区间去找当前无序区间的最大值(升序找最大值,降序找最小值),而堆排序呢是吧无序区间原创 2021-08-30 20:26:16 · 3574 阅读 · 14 评论 -
都是❤️两层循环❤️的冒泡排序,选择排序,插入排序该怎么区分
目录冒泡排序选择排序插入排序这三个排序都有两层循环这是他们表面的特点,我把外部循环叫大循环,内部循环叫小循环,他们算法根本思想都有相同点,就是将待排序序列分为无序区间和有序区间,每过一次大循环都能让有序区间增加一个相应的无序区间减少一个:科普一下这种每次通过相同操作让问题规模减小的算法称为减治算法,现在我们清楚了他们的底层思想,再来分别讨论以作区分。冒泡排序各位同学接触最早的排序算法应该就是冒泡排序了,他的过程如下图所示:拿图中升序举例他每次小循环都会从0开始在遍历的过程中将遇到的最大的数像冒原创 2021-08-29 12:16:52 · 311 阅读 · 32 评论 -
建堆解决TopK问题
对于找海量的数据中最大(小)个数据的问题被称为TopK问题。解决这个问题的方法有很多比如排序然后相应的取前K个数据,排序的算法有很多种,其中不乏时间复杂度低的,可问题很多排序算法都需要将所有数据同时加载到内存中去处理,海量数据加载到内存中这无疑是一个很废内存空间的操作,而建堆解决TopK问题就可以解决这个问题。先将建堆操作的结论告诉大家:要TopK最大的就建小堆要TopK最小的就建大堆为什么要反着来呢?我们来讨论具体操作思路。拿TopK最大举例,要找K个最大数据就先建立一个能放K个数据的小堆原创 2021-08-28 16:36:03 · 121 阅读 · 0 评论 -
数据结构之堆(Heap),堆的相关操作,用堆模拟优先级队列
目录堆的概念堆的存储方式堆的相关操作堆的向下调整。堆的创建堆的插入和向上调整堆的删除用堆模拟优先级队列堆的概念堆是逻辑结构为二叉树存储结构为数组数组的一种数据结构,为什么这么说呢?因为我们就是把堆想象成一棵有特殊功能的二叉树,然后把它按照层序遍历的顺序放到数组中。堆有大堆小堆之分,大堆是指根节点为堆中最大值的堆,小堆是指根节点为堆中最小值的堆。堆中某个节点的值总是小于等于或大于等于其父亲节点的值,前者称为就是大堆,后者为小堆。堆总是一棵完全二叉树。小堆:大堆:可以看到小堆的父亲节点都小于原创 2021-08-27 23:55:40 · 264 阅读 · 2 评论 -
Java中的PriorityQueue优先级队列
以前的博客中介绍过队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,此时出队列时需要优先级高的元素先出队列,这个时候传统的队列显然不能胜任,Java中有一个新的实现类继承了Queue接口,这个类实现了上述优先级队列——PriorityQueue。PriorityQueue是怎么知道队列中哪个元素优先哪个元素不优先的呢?Java中的Comparable和Comparator到底该怎么用看完就全明白了大家可以看一下我这篇文章(不看不影响,看理解的更深刻)有两个路子:队列中对原创 2021-08-27 00:21:35 · 179 阅读 · 4 评论 -
Java中的Comparable和Comparator到底该怎么用看完就全明白了
很多同学搞不清楚Comparable和Comparator这两个接口,单看这两个单词,一个是形容词一个是名词,但是可以看出来都和比较有关,我个人把实现了Comparable接口的某个类理解成这个类具备了比较能力,而把实现了Comparator的类称为比较器类,那么他们分别该怎么用呢?目录Comparable(比较能力)PriorityQueue队列Comparator(比较器)小结Comparable(比较能力)PriorityQueue队列在正式介绍他们俩之前,先给大家介绍一下Java中的优先级队原创 2021-08-26 21:41:49 · 873 阅读 · 18 评论 -
二叉树最简单的遍历方式——二叉树的层序遍历
遍历分为深度优先和广度优先,对于二叉树的深度优先遍历我们已经讨论过了常规的递归遍历,迭代遍历和优化了空间复杂度的Morris遍历,这篇博客我们来讨论二叉树的广度优先遍历,也就是我们常说的层序遍历。以下图中二叉树为例:顾名思义二叉树的层序遍历是一层一层的顺序遍历的,上图的二叉树遍历顺序是: A B C D E F G H。层序遍历大体的遍历方向是由浅到深,由左到右,也就是下图中箭头所示方向:对于递归遍历和迭代遍历都是关于栈的应用,而层序遍历是关于队列的应用,代码层面的思路是,创建一个队列,根节点先原创 2021-08-23 00:25:49 · 311 阅读 · 9 评论 -
彻底理解被称为二叉树神级遍历的莫里斯(Morris)算法
二叉树的遍历我们已经介绍过了最常见的递归遍历:用Java描述数据结构之二叉树,前序遍历,中序遍历,后序遍历和迭代遍历二叉树前序,中序,后序遍历的迭代实现,实现思路及代码上面两种遍历虽然看上去不同,但是底层的思路是大同小异的,都是调用栈,递归是用java虚拟机栈,而迭代使用我们自己创建的栈。今天要介绍的莫里斯算法,它的背后没有用任何栈相关的知识,而且相比于前两种空间复杂度为O(n)(因为进栈最差会所有数据全部进栈)的遍历来说,莫里斯算法的空间复杂度只有O(1),这对于量很大的数据来说无疑是天上地下的区别。原创 2021-08-22 18:41:45 · 4005 阅读 · 17 评论 -
二叉树前序,中序,后序遍历的迭代实现,实现思路及代码
用Java描述数据结构之二叉树,前序遍历,中序遍历,后序遍历这篇博客中我介绍了二叉树的相关概念和递归实现的二叉树的前中后序遍历。今天来介绍非递归迭代版遍历的思路及实现代码。首先我们要明白所谓遍历就是集合中每个节点都要经过,就下面这棵树而言,我们从根节点开始要怎么走才能经过每个节点?下面是上图树的构建代码:public static TreeNode buildTree() { // 博客中所用到的树的构建 TreeNode a = new TreeNode('a');原创 2021-08-19 15:06:04 · 943 阅读 · 13 评论 -
哪两种遍历方式可以唯一确定一棵二叉树,结合力扣105题
对于一棵树的前中序三种顺序的遍历方式,任何一种单独拿出来都无法确定一棵树,那么两种遍历方式得到的节点数据能否组成一棵二叉树呢?先来看看能有哪几种组合:先序遍历 + 中序遍历后序遍历 + 中序遍历先序遍历 + 后续遍历(不可行)以上三种组合都可以组成二叉树,但是只有前两种组合可以唯一确定一棵二叉树,最后一种也就是先序遍历 + 后序遍历无法唯一确定一棵二叉树。为什么呢?下给出一棵树的前中后序遍历:先序遍历:A B D H L E C F I J M N G K中序遍历:D H L B E A原创 2021-08-18 23:46:11 · 8194 阅读 · 2 评论 -
二叉树的旋转,左旋和右旋
在AVLTree中经常会有以某个节点为点对子树进行旋转的操作,今天就和大家分享一下什么是二叉树的旋转。这是一棵二叉树,上图称为图一。将图一中的树以1为旋转点进行左旋后得到图二:将图一中的树以1为旋转点进行右旋旋后得到图三:将图三一节点1为旋转点点做右旋得到图四:看了几次左旋和右旋之后相信有很多同学已经明白了什么是左旋,什么是右旋,如果还不清楚的话,请结合下面的结论再去理解上图。左旋:旋转点的右子树(包括旋转点)成为旋转点左子树的根节点的右子树,旋转点左子树的根节点的原右子树变为原旋转点的原创 2021-08-17 00:54:26 · 2935 阅读 · 1 评论 -
二叉树节点数目计算的两种思路
介绍两种思想,虽然根本上都是遍历每个结点,但是在写代码的时候采用的是不同的思想。遍历思想先定义一个类变量就是采用二叉树遍历的代码,在经过每个节点的时候类变量++,具体代码如下:public class CountTreeNodeSize { public static int count = 0; //任何一种遍历方法都可以 public static void countTreeNodeSize1(TreeNode root){ if (root == nul原创 2021-08-10 11:38:44 · 727 阅读 · 0 评论 -
树的常见概念,二叉树的性质
树的常见概念节点的度:树的度:叶子结点或终端节点:双亲节点或父节点:孩子节点或子节点:根节点:节点的层次:输的高度或深度:下面概念只需了解非终端节点或分支节点:兄弟节点:堂兄弟节点:节点的祖先:子孙:森林:二叉树的性质...原创 2021-08-09 00:00:03 · 110 阅读 · 2 评论 -
老师说过链表是分水岭,至少得会这些题目
目录1.删除链表中等于给定值 val 的所有节点在记录作者自己学习过程和解题时的思路方便复习的同时分享给其他同学们,如有错误或不足还请指正。1.删除链表中等于给定值 val 的所有节点题目链接:https://leetcode-cn.com/problems/remove-linked-list-elements/description/解法一:创建一条新链表,遍历旧链表,将不等于定值val的节点加入到新链表,...原创 2021-07-29 12:23:55 · 60 阅读 · 0 评论 -
什么是循环队列?循环队列及其实现,结合LeetCode第622题(设计循环队列)来介绍
如果对队列还有些疑问的可以线看一看我上一个博客:用Java描述数据结构之栈和队列,以及栈和队列的常用方法当我们只有一段固定大小空间去存一个队列时像这样:Front是队首,Rear是队尾,很明显这个空间已经满了,现在依次删除队首元素:可以发现随着队列内元素越来越少,没有用到的空间越来越大,且总空间大小不变,所以说到最后这段空间就算是废了。为了让这段空间可持续利用,我们其实可以这样:就是每次头删之后将队列中所有元素向前移,这就很好的解决了问题,完美的提升了空间的利用。可是,每头删一个元素都依次原创 2021-04-01 20:53:11 · 452 阅读 · 0 评论 -
用Java描述数据结构之栈和队列,以及栈和队列的常用方法
一般都是在学完线性表(顺序表和链表)之后,才会去学习栈和队列,因此可能会觉得栈和队列是一种新的数据结构,其实不然。它们逻辑上还是一对一的关系,所以说它们本质还是线性表,只不过是加了一定限制的线性表,具体加了哪些限制,且听我娓娓道来。栈这是一个线性表,我们可以对这个这个线性表内的任何一个元素进行需要的操作,我可以删掉既不是头也不是尾的[ 2 ]号元素,也可以在 [ 1 ]号位插入新的元素,就是说你对这个线性表里面的任何一个元素操作都是可以的,现在你把它放依次放到一个杯子里面。可以看到最先进去的[ 0原创 2021-04-01 00:30:47 · 215 阅读 · 2 评论 -
用Java实现一个简单的链表迭代器
迭代器有两个功能:boolean hasNext():查看是否还有下一个元素E next():返回当前元素先上代码这是迭代器所用到的节点类:public class MyListNode { public String val; public MyListNode prev; public MyListNode next; public MyListNode(String val){ this.val = val; }}迭代器类:public clas原创 2021-03-29 22:35:43 · 331 阅读 · 0 评论 -
用Java描述数据结构之线性表的链式存储(链表),模拟LinkedList实现
上一篇介绍了顺序表:用Java描述数据结构之线性表的顺序存储(顺序表),ArrayList及其方法的介绍上一篇博客中说明了什么是线性表——线性表就是一个个数据元素逻辑上以一对一的相邻关系(但是在物理结构上并不一定是连续得到)组织起来的有限序列。根据物理存储方式的不同可以将线性表分为两种,一种叫顺序表,一种叫链表,这篇博客主要介绍链表。链表和顺序表不同,链表在存储时并不是连续的,大家可以这么理解:内存上被使用的一段段空间之间会有小段的未被使用的,链表在使用时就可以使用这些小段的未被使用的空间去存储数据,原创 2021-03-29 22:01:36 · 302 阅读 · 0 评论 -
用Java描述数据结构之二叉树,前序遍历,中序遍历,后序遍历
什么是二叉树?一棵二叉树是节点的一个有限集合,该集合或者为空,或者是由一个节点加上两棵别称为左子树和右子树的二叉树组成。根据二叉树的概念,可以知道二叉树有以下两个特点:1.每个节点最多有两棵子树,即二叉树不存在度大于二的节点。2.二叉树的子树有左右之分,其子树的次序不能颠倒,因此二叉树是有序树。二叉树的基本形态:上图给出了几种特殊的二叉树形态,从左往右依次是:空树、只有根节点的二叉树、节点只有左子树、节点只有右子树,一般二叉树都是由上述基本形态结合而成。两种特殊的二叉树:满二叉树:一个二原创 2021-03-24 17:02:34 · 346 阅读 · 3 评论 -
用Java描述数据结构之线性表的顺序存储(顺序表),ArrayList及其方法的介绍
我们先来想一想什么是线性表?线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储,但是把最后一个数据元素的尾指针指向了首位结点)。以上是百度百科中介绍的线性表,说白了线性表就是一个个数据元素逻原创 2021-03-21 21:39:05 · 267 阅读 · 0 评论