- 博客(22)
- 资源 (1)
- 收藏
- 关注
原创 无锁实现单例模式+cas、乐观锁、悲观锁、自旋锁的理解
在我们平常中的单例模式之懒汉式的实现下,为了线程安全,我们一般都是通过加锁的形式实现的,有双重检查锁,synchronized、静态内部内(通过类的加载机制实现的,在类加载中加了synchronized)等等,大家有兴趣可以去看我的另一篇文章实现单例模式的常规形式那如果我们在面试中遇到:如何无锁实现懒汉式呢?这里我提供一种思路:我们可以借助于cas进行无锁实现cas(compare and set):这是一个原子性的操作,属于乐观锁的行列,它包含 3 个参数CAS(V,E,N),V表示要更新
2022-04-03 12:31:11
940
原创 设计模式之单例模式
单例模式大致介绍相信接触java的小伙伴都对单例模式有一点了解。单例模式属于创建型模式,其主要为:在一个系统或一个项目中,我们对于某一类对象只创建保存维护一个实例。在我们常用的单例模式主要分为两种,一种是饿汉式,一种是懒汉式。饿汉式与懒汉式的主要区别为:饿汉式是对象随着类的加载而创建,即一开始便创建好了对象,而懒汉式是指在你调用时才会创建对象。由其区别,可以分析:饿汉式的主要优点为:实例是随着类的加载而加载的,故此避免了线程同步问题,而且较为简单;缺点也很明显:如果没用到懒汉式的
2022-01-25 13:00:38
1154
原创 springboot实现项目注册邮箱验证码的发送
在我们项目的注册业务模块中,我们一般会有邮箱验证这个部分(也可以采用短信验证,但阿里云和腾讯云的短信服务申请比较麻烦,所以我就以后端接口实现为例,写一写邮箱验证)。那我们如何实现呢?这里我以QQ邮箱为例,首先我们打开QQ邮箱首页,点开设置点账户移到最下面,会有个开启服务,这里我们选择开启POP3/SMTP服务。在点开启后,会需要让你验证手机密保,我们只需要跟着验证就好了,验证完会有一个密匙,是一个一连串的英文字母组成的密匙。这一步完成后。我们就打开我们的idea,引入相关依...
2021-10-28 16:44:32
833
原创 论list接口有序与set接口无序
我们知道,set接口是用来存储无序且不可重复的数据,而list接口是用来储存有序、可重复的数据但是,为什么set接口的实现类treeSet、hashSet却是有序的呢?这里可能比较容易搞混。我们这里说的有序无序指的是:按照添加的顺序来输出,即为有序,否则为无序。如图我们发现,set接口的实现类不以添加的顺序进行遍历,而list接口的实现类是以添加的顺序进行遍历的。set接口储存无序的数据,实质是指,其不按照添加的顺序进行输出,所以为无序。我们知道:hashSet.
2021-10-07 19:07:10
777
原创 常用十大算法
这里的讲解图主要使用的是尚硅谷韩顺平老师的图,请周知。目录二分查找(非递归)分治算法动态规划算法KMP算法贪心算法普利姆(Prim)算法克鲁斯卡尔(Kruskal)算法迪杰斯特拉(Dijkstra)算法弗洛伊德(Floyd)算法骑士周游算法总结二分查找(非递归)二分查找(非递归)算法:前面我们涉及的是递归实现二分查找算法。如今实现的是非递归的方式。同样,二分查找只适用于有序数列。二分查找的运行时间为对数时间O(log2n),即查找到需要的目标...
2021-09-25 17:08:55
7401
原创 图的深度优先遍历及广度优先遍历
图的引出:前面我们学了线性表和树。线性表局限于一个直接前驱和一个直接后继的关系;树也只能有一个直接前驱也就是父结点。但我们需要表示多对多的关系时,我们就需要用到图这种数据结构。图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表)。邻接矩阵中,如果两个顶点相连通,则为1,如果不连通,则为零。图的遍历:有两种策略。1、深度优先遍历(Depth First Search)。2、广度优先遍历(Broad First Search)。深度优先遍历思想:深度优先遍历是一种纵向切入..
2021-09-20 22:14:36
7657
原创 堆排序思路及其实现
我们之前提到过七大排序算法,现在来补充第八种排序算法——堆排序。那什么是堆排序算法呢?堆排序:堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序其实是一种选择排序,其最坏、最好,平均时间复杂度均为O(nlogn),且是一种不稳定排序。堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆,注意:没有要求结点的左孩子的值和右孩子的值的大小关系;每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。升序操作使用大顶堆,降序操作使用小顶堆。堆排序的基本思想:
2021-09-20 21:03:53
253
原创 简单介绍B树、B+树、B*树
B树、B+树、B*树都是属于多路查找树二叉树与B树:引出:二叉树存在的问题是如果数据量过于庞大,则会出现很多分支或者分支很长的情况,这个时候就会导致检索、构建二叉树的速度变慢。而且在构建二叉树的时候会有频繁的IO操作。多叉树通过重新组织结点,降低树的高度,能对二叉树进行优化。二叉树中,每个节点有数据项,最多有两个子节点。如果允许每个节点可以有更多的数据项和更多的子节点,就是多叉树(multiway tree)2-3树是最简单的B树结构,其有如下特点:1)2-3树的所有叶子结点都在同一层
2021-09-20 17:37:58
331
原创 二叉树(顺序存储二叉树、线索化二叉树、赫夫曼树、二叉排序树、平衡二叉树)
这里我就不对树的一些名词做解释,有需要的可以去百度了解树的名词,比如结点、权值等。树的遍历方式有三种,分别为前序遍历、中序遍历、后序遍历。前序遍历:先输出父节点,再遍历左子树和右子树中序遍历:先遍历左子树,在输出父节点,再遍历右子树后序遍历:先遍历左子树,再遍历右子树,最后输出父节点。...
2021-09-20 17:32:38
572
原创 哈希表的原理与实现
哈希表也称散列表,是由数组+单链表构成的一种数据结构,它是根据关键值(key-value)进行对数据的访问的,它通过把关键码值映射在表中的一个位置来访问记录,以加快查找速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。其底层如图:所以,由此可见我们的哈希表实质就是一个链表的数组,即linkedList[] hashtable 。对于创建哈希表,我们首先需要创建一个单链表,并且创建一个类,作为链表中添加的数据。这里我就创建了一个Emp类,属性有id,name,next。作为链表中.
2021-09-12 16:36:04
992
原创 三大查找算法(原理+实现)
下面我介绍的是二分查找算法(递归实现)、插值查找算法(递归实现)、斐波那契查找算法(递归+非递归实现) 查找算法在我们不论是面试、工作中都十分重要,在海量数据中,如何提高查找效率,也是我们程序猿一直追求的目标。现在我就介绍其中最普遍的三种查找算法,希望对大家有所帮助。首先,以上三种查找算法都基于同一个前提:就是有序所以我们在进行查找之前,必须先对数组进行排序,而如何排序呢?我在之前的一篇文章有讲到对应的7大排序算法,用兴趣的朋友可以先去了解一下(链接附上),这里我就不再赘述了,直接进入正题...
2021-09-12 11:14:35
1890
原创 七大排序算法 思路及其实现
这里我会介绍冒泡、选择、插入、希尔、归并、快速、基数排序算法,而堆排序在后续的更新中会介绍这种排序算法(介绍完树后)稳定性的概念为:假如要排序的数列出现了相同的数据,则原本在左边的数据仍然在左边,右边的数据仍然在右边,即不会改变这两个数据的顺序,这种情况成为稳定。我们这里都实现从小到大排序目录冒泡排序选择排序插入排序希尔排序交换式实现希尔排序:移位式实现希尔排序:快速排序:归并排序基数排序:总结:冒泡排序冒泡排序是一种通过不断交换相...
2021-09-11 17:29:50
996
1
原创 八皇后问题的解决(递归)(后附完整实现代码)
八皇后问题主要是:在一个8*8的棋盘上,放置八个皇后,这八个皇后不能处在同一行、同一列以及统一斜线,问符合要求的安置方法有多少种情况?高斯说64种,随着计算机的高速发展,而今人类用计算机计算得出的记过是92种,那我们是如何借助计算机实现的呢?首先,我们先聊聊思路要点:1.理论上是需要创建一个二维数组来记录棋盘的,但是这里数组比较多位置会是没有落子的,即都为0 既为了节省空间,也为了简便,故我们这里可以直接创建一个一维数组 下标代表行数,数组内的值代表列数,如arr[1]=3,即代表落子.
2021-09-09 17:17:34
561
原创 前中后缀表达式以及 中缀表达式转后缀表达式的实现
前缀表达式、中缀表达式(波兰表达式)、后缀表达式(即逆波兰表达式)前缀表达式: 运算符在要计算的数字之前 如- * + 3 4 5 6(此时需从右往左扫描,遇到运算符就计算) 转为中缀表达式为(3+4)*6-6如从右往左扫描扫描6 5 4 3 + 扫到运算符后,弹出栈顶的两个数字,即3 4 然后进行运算,即3+4 = 7,后续同理中缀表达式:运算符在计算的数字之间 如7*2+3-1后缀表达式:运算符在计算的数字之后 如3 4 + 5 * 6 –(此时需从左往右扫描,遇到运算...
2021-09-08 22:58:59
213
原创 借助栈实现一个中缀表达式的计算器
我们一般给出的一个表达式是如 String expression = "7*20-1*4*2+3"这样的字符串,但是如果让我们通过程序去计算这样的一个表达式该如何实现呢?这里的计算器只是为了展现栈这种数据结构的运用,没有涉及小数、括号的运算,有兴趣的码友可以在此基础上进行完善。这里我们可以借助栈的数据结构来实现计算器,那么如何实现呢?首先,我们需要先创建两个栈,一个是符号栈,一个是数字栈。符号栈是用来记录运算符,而数字栈是用来记录数字。我们以一个简单表达式 String expression =
2021-09-08 17:23:51
202
原创 约瑟夫问题的解决(后面附有完整实现代码)
首先我们先明确什么是约瑟夫问题:约瑟夫问题:设编号为1、2、....n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列思路:先创建一个环形链表,环形链表通过for循环来创建,关键要形成一个循环。 创建一个方法getCount(),计算出链表的有效数据的个数,通过循环遍历的方式获取链表的有效数据作用:创建一个数组来存储出队...
2021-09-07 21:59:01
673
原创 双向链表的创建与CRUD的实现
链表是由结点的方式来储存的,是链式存储。其的组成需要有data(数据域),指向下一个结点的next,指向前一个结点的pre(双向链表)。链表可以分为有头结点和无头结点的链表。注意:链表是一种逻辑上的顺序存储结构,而物理上不一定是顺序存储结构。(即在实际计算机存储中不一定是按照顺序存储的,但在我们的逻辑上认为,它们就是连续存储的)双向链表问题主要是针对于指针的使用要弄清楚,这里我们要引入两个指针,一个是pre,一个是next。pre指针指向的是上一个结点,next指向的是下一个结点。至于单向链表的实现
2021-09-07 17:03:14
144
原创 腾讯面试题:单链表的反转
要实现单链表的反转,我们首先需要创建一个单链表并实现CRUD操作,因我之前已写过类似的文章,故不再赘述,在此附上链接创建单链表并实现CRUD单链表反转的思路:首先我们创建一个新的辅助链表并获取其头结点,我们通过两个指针next,cur;cur指针指向当前遍历到的结点。next指针指向当前遍历到的结点的下一个结点。我们每遍历一个新的结点,就把这个结点放到新的这个头结点的最前面的位置,如此叠进,就能获得一个新的反转的单链表,最后再把head的next指向辅助链表的头结点的下一个结点。下列是代
2021-09-07 16:09:01
310
原创 新浪面试题:查找单链表中的倒数第k个结点
对于该面试题,首先我们先创建一个单链表实现CRUD操作,由于我之前已写过对应的文章,现在下面附上链接,这里不再赘述。创建单链表并实现CRUD操作对于该面试题,我们的思路是:首先,获取到该单链表的有效数据的总数count,然后定义一个index=0的指针,且需要一个临时结点cur,cur指向当前遍历到的有效数据,通过一个循环,当index==(count-k)时,此时就可以得到确切位置的结点。详见代码如下:package com.liu.linkedlist;/** * @author
2021-09-07 15:26:36
313
原创 单向链表的定义与CRUD
链表是由结点的方式来储存的,是链式存储。其的组成需要有data(数据域),指向下一个结点的next,指向前一个结点的pre(双向链表)。链表可以分为有头结点和无头结点的链表。注意:链表是一种逻辑上的顺序存储结构,而物理上不一定是顺序存储结构。(即在实际计算机存储中不一定是按照顺序存储的,但在我们的逻辑上认为,它们就是连续存储的)单链表:单链表顾名思义,就是只有单向存储,没有双向存储,也即只有一个next结点,没有pre结点。这里可以分为直接把数据添加到末尾和根据数据大小插入到指定的位置。注意点:因为
2021-09-07 09:59:57
306
原创 环形队列的实现
首先我们先来了解一下队列是什么?队列:数据先入先出,后进后出(与栈刚好相反),主要通过数组实现。需要通过两个指针来创建对应的队列;一个指针为前缀pre,一个指针为后缀rear。pre指针指向先进来的数的前面,rear指针指向数组的加入数,即有数据的末尾,以此来判断加入的数组是否已满。(我们这个pre指针指向的是首个数据的前面(要保证先进先出,就得要有个指针指向数据的第一个),而rear指向的是数据中的最后一个数据)这是我对于队列的总结,但这只是普通队列,该种方式实现的队列只能使用一次(大家有兴.
2021-09-06 22:44:40
673
原创 稀疏数组的定义及作用与代码实现
大家好,这是我学习完尚硅谷韩顺平老师的《数据结构与算法》后,进行复习回顾,自己对于稀疏数组的理解。什么是稀疏数组呢?首先我引出一个例子,就是五子棋,我们对于五子棋有存盘与复盘,如果要存盘的话,我们一般会使用一个二维数组进行存储。但这里就引出了一个问题,假设说,棋子在棋盘上的覆盖率不高,那我们对用于存储数据的二维数组是否会有很多空位呢。借助韩老师的图进行一个解释,如上图,此时用1表示黑子,2表示蓝子,0表示未有棋子的区域。由上图我们可以看出,中间的棋盘中有很大的一部分区域是没有落子的.
2021-09-06 22:29:34
362
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人