数据结构
反复敲代码
一颗苹果.
是谁说蓝色就等于忧伤 你看看天空和海洋~
展开
-
哈希表
1. 什么是哈希表想要查找一个元素方法有很多,比如说查找数组中的某个元素,直接遍历数组,依次判定比较,时间复杂度为O(N);或者将数组排成有序数组,再采用二分查找,时间复杂度为O(NlogN);还可以将数组的内容放到二叉搜索树中,时间复杂度为O(N)。那么能不能通过key,不需要遍历和比较,就能直接得到对应的value呢?为了实现这样的思想,于是就有了哈希表,奥秘就是借助了数组取下标的时间复杂度为 O(1),借助了内存的随机访问能力。即将 key 通过一定的数学变换,映射到数组下标上,如下示例:原创 2021-03-31 16:52:49 · 103 阅读 · 0 评论 -
二叉搜索树的查找插入和删除
1. 什么是二叉搜索树对二叉搜索树进行中序遍历,其结果是有序的。 若左右子树不为空,左子树上所有节点的值小于根节点的值,右子树上所有节点的值大于根节点的值。2. 实现二叉搜索树的 查找、插入、删除操作2.1 先准备一个二叉搜索树的节点class BinaryNode{ int key; int value; BinaryNode left; BinaryNode right; public BinaryNode(int key, int val原创 2021-03-30 17:22:05 · 269 阅读 · 0 评论 -
Map和Set的常用方法和注意点
Map 和 Set 两个接口分别被 HashMap、TreeMap 和 HashSet 和 TreeSet 实现。HashMap 和 TreeMap 两者用法相同,只是底层实现不同,HashSet 和 TreeSet 也一样。下面就以 HashMap 和 HashTree 为例。1. Map接口里面存储的是<key,value> 键值对,key一定是唯一的,不能重复,就像不同的身份证对应到不同的人。1.1 Map的常用方法① 增加,通过 put() 方法增加键值对Map..原创 2021-03-30 15:29:40 · 751 阅读 · 0 评论 -
[实现+性能分析] 七种常见的排序算法!!!
使一串数据,按照递增或者递减的顺序排列起来,这个操作称为排序,通常意义上的排序,指的是原地排序。===========本篇文章均以升序为例==========1. 性能分析的方法① 时间复杂度② 空间复杂度③稳定性两个相等的数据,排序前和排序后的相对位置相同,那么就称这种排序是稳定的,反之,不稳定。上图中,升序排序前,红2在黑2的后面。经过方法①的排序之后,红2依然在黑2的后面,相对位置保持不变,所以认为算法①是稳定的;经过方法②排序后,红2跑到了黑2的前面,算法②不稳定.原创 2021-03-25 12:50:07 · 283 阅读 · 0 评论 -
优先级队列(堆)
目录1优先级队列1.1 什么是优先级队列?1.2 PriorityQueue的使用2什么是堆?2.1 概念2.2 性质2.3大堆和小堆3 堆的基本操作3.1建立堆3.2插入元素3.3获取堆顶元素3.4删除堆顶元素1优先级队列1.1 什么是优先级队列?有的情况下,我们操作的数据可能带有优先级,比如众多作业中先写语文作业还是先写数学作业,按照我的理解,我认为哪个先交我就先写哪个,或者有的同学可能认为,对哪个更感兴趣就先写哪个。之前我们学...原创 2021-03-23 16:44:36 · 152 阅读 · 0 评论 -
非递归实现二叉树的先中后序遍历
1. 先序遍历1.1 思路①创建一个栈 ②将根节点入栈 ③取出栈顶元素并访问 ④将其右子树入栈,左子树入栈 ⑤回到③重复1.2 代码//这里先序遍历创建一个栈,根->右->左public static void preOrder(TreeNode root){ if(root==null){ return; } Stack<TreeNode> stack=new Stack<>(); stack.p原创 2021-03-21 23:16:34 · 95 阅读 · 0 评论 -
二叉树
目录1.二叉树的特点2.二叉树的基本操作(使用链式存储结构实现)2.1 准备工作2.2前序遍历2.3中序遍历2.4 后序遍历2.5 求节点个数(两种方法)2.6 求叶子节点的个数(两种方法)2.7 求第k层节点个数2.8 获取二叉树的高度2.9 查找val所在的节点3.练习题目3.1 二叉树的前序遍历(题目链接)3.2 二叉树的中序遍历(题目链接)3.3二叉树的后序遍历(题目链接)3.4 检查两棵二叉树是否相同(题目链接)3.5 判断...原创 2021-03-14 16:08:27 · 292 阅读 · 0 评论 -
栈和队的练习:实现一个最小栈
题目描述(题目链接)实现一个能求出当前栈中最小元素的栈思路创建两个栈,A,B A中存所有入栈的元素,B中存当前栈中的最小元素,最小元素为B的栈顶 入栈时,如果元素小于或者等于B的栈顶,A和B均入栈,反之,只给A入栈 出栈时,如果A的栈顶元素等于B的栈顶元素,那么A和B均出栈,反之,只给A出栈 取栈的最小元素,即取B的栈顶元素代码class MinStack { Stack<Integer> A=new Stack<>(); Stack<原创 2021-03-11 20:50:01 · 57 阅读 · 0 评论 -
栈和队的练习:用两个队列实现栈
题目链接思路主要是在出栈和取栈顶元素问题上 只要明确,出栈出的就是队列的队尾元素,所以只要获取到队列的队尾元素即可(如果不理解可以画一个栈和一个队,入相同的元素,可以发现栈顶即是队尾) 取栈顶元素就是取到队列的队尾元素 实现上,我们创建两个队列A,和B。A中始终保存入队的元素。将A中的元素挪到B中,当A中只剩一个元素时,也就是我们想要的队尾,即出栈的元素,也就是栈顶,将其保存返回即可,此时所有的元素在B中,我们再将A,B交换,始终保证A中是存入队的元素。代码//用两个队列实现栈cla原创 2021-03-11 20:02:54 · 88 阅读 · 0 评论 -
栈的练习:括号匹配问题
题目链接思路首先创建一个栈 charAt遍历字符串,如果字符为左括号,那么就入栈 遇到右括号,将栈顶元素取出来比较是否和右括号匹配,如果匹配,就删掉栈顶元素继续循环,否则返回false 全部遍历完成之后,判断栈是否为空,如果栈为空,说明全部匹配完成,返回true,否则返回false代码import java.util.Stack;public class Solution1 { public boolean isValid(String s) { Stack&原创 2021-03-11 19:08:30 · 104 阅读 · 0 评论 -
Java:自己实现栈和队列
一、什么是栈,什么是队列?栈:栈的特点是后进先出,也就是从哪边进从哪边出(就像装在罐子里的糖果,最后装进去的,最先被取出来)队列:队的特点是先进先出,也就是从哪边进,从另一边出(就像我们排队买饭一样,先排队的人先买到饭)二、自己实现栈核心操作:入栈push(把元素放到栈里面),出栈pop(把最后进来的元素删掉),取栈顶元素peek(获取到最后一个进来的元素的结果)2.1 使用顺序表实现尾插尾删即可(不建议头插头删,由于顺序表是基于数组实现的,如果头插头删,可能会存在大量的挪动元素,效原创 2021-03-09 13:39:33 · 160 阅读 · 0 评论 -
顺序表实现实现一副扑克牌的洗牌发牌功能
通过这个小游戏回顾一下顺序表的知识~一副扑克牌中有很多张卡片,每个卡片是由花色和点数组成的,所以我们先创建卡片这个类,属性为花色和点数。public class Card { public String huaSe; public String point; public Card(String huaSe, String point) { this.huaSe = huaSe; this.point = point; }原创 2021-03-07 20:26:14 · 387 阅读 · 1 评论 -
自己实现链表的增删改查
目录 创建节点类 准备工作 插入元素(增) 查找元素 删除元素 修改元素 总结一、创建节点类标准库中的LinkedList是双向链表,所以在实现的时候需要prev和next两个引用,为了方便后续测试代码,自己重写了toString方法,方便打印。class Node{ int val; Node prev; Node next; publ...原创 2021-03-07 12:00:30 · 126 阅读 · 0 评论 -
对比顺序表和链表
顺序表优点:顺序表存储在连续的空间上,是基于数组实现的,支持随机访问缺点:①中间或前面部分的插入删除时间复杂度为O(N) ②增容的代价比较大链表优点:①链表是存储在不连续的空间上,提高了空间的利用率②头删头插的效率较高缺点:不支持随机访问标准库中的LinkedList(双向链表),增删改查的时间复杂度都是O(N),都是要先遍历链表,找到相关的节点,再进行操作,特殊情况例外,比如头删头插,尾删尾插。现在的链表和顺序表相比,最大的优势就剩下头插头删的效率了。...原创 2021-03-06 17:24:15 · 88 阅读 · 0 评论 -
返回链表的入环节点
思路首先判断链表是否存在环,如果不存在直接返回null(快慢指针判断链表是否有环博客链接) 从两个快慢指针交汇的地方到入环节点的距离和从链表第一个节点到入环节点的距离是相同的创建两个引用cur1,cur2,分别指向链表的第一个节点和快慢指针交汇的地方,两个引用重合的地方便是链表的入环节点代码public class Solution11 { public ListNode detectCycle(ListNode head) { if(head==null||he原创 2021-03-06 15:05:56 · 316 阅读 · 0 评论 -
判断链表中是否有环
思路快慢指针的方法 定义两个引用fast,slow,初始情况下均让其指向链表的头节点,fast每次走两步,slow每次走一步 判断是否存在两个引用指向同一个节点相同的情况 若存在,存在环,反之,不存在环代码public class Solution10 { public boolean hasCycle(ListNode head) { if(head==null||head.next==null){ return false;原创 2021-03-05 19:20:28 · 96 阅读 · 0 评论 -
找到两个链表的第一个公共节点
思路两个相交的单链表,不可能是x型,只可能是Y型,因为相交处的节点只有一个next,只能保存一份地址,也就是说从相交的节点开始,后面每个节点都是同一个节点了 假设有两个链表A链表和B链表 先得到两个链表的长度lenA,lenB 如果lenA>lenB,那么先让A链表走lenA-lenB步,反之,让B链表走lenB-lenA步 遍历比较指向链表的两个引用(引用中存的是地址,==比较身份,也就是比较地址是否相同),如果相等就返回这个引用指向的节点,遍历结束没找到就返回null原创 2021-03-05 18:38:40 · 100 阅读 · 0 评论 -
链表的回文结构
题目要求判断一个链表是否为回文结构,返回boolean类型思路将原链表复制一份,到新的链表中 逆置新的链表(如何逆置链表博客链接) 逆置后的新链表和原来的链表进行比对代码public class Solution8 { public boolean chkPalindrome(ListNode A) { if(A==null||A.next==null){ return true; } ListNode原创 2021-03-05 17:58:14 · 58 阅读 · 0 评论 -
删除排序链表的重复节点
题目描述在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5思路创建一个新的链表,为了方便尾插,使其带傀儡节点 遍历原有链表,由于是排序的链表,所以重复的节点肯定是相邻的,找到不重复的节点,插入新的链表尾部即可 返回新链表头节点的下一个节点代码public class Solution7 { public Li原创 2021-03-05 16:05:08 · 210 阅读 · 0 评论 -
给定值将链表分割成两部分
题目描述给定值x将链表分割成两部分,比x小的在链表的前面部分,比x大的在链表的后面部分,不能改变原来的数据结构思路创建两个新的链表(为了方便插入元素,使其带傀儡节点):smallList,largeList 遍历链表,比x小的,插入到smallList链表的末尾,比x大的插入到largeList的末尾 最终合并两个链表代码public class Solution6 { public ListNode partition(ListNode pHead, int x) {原创 2021-03-05 15:27:38 · 182 阅读 · 0 评论 -
将两个升序链表合并为一个新的升序链表
思路创建一个新的链表用来保存合并结果,为了方便插入,使其带傀儡节点,定义一个引用tailNode,使其指向链表的末尾 创建两个引用head1,head2,分别指向两个待合并的链表的第一个节点,比较head1的val和head2的val,小的一个插入到新链表末尾,更新即可 直到其中某个链表为空了,那么就将另外一个链表的剩余部分全部插入到新链表的末尾 由于新链表是带傀儡节点的链表,最终返回新链表头节点的下一个节点即可代码public class Solution5 { public L原创 2021-03-05 14:39:35 · 2047 阅读 · 0 评论 -
链表的中间节点
题目描述给定一个头结点为head的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。思路求出链表的总长度 总长度/2就是要走的步数,for循环从链表头节点遍历即可代码public class Solution3 { public int getLength(ListNode head){ int len=0; for(ListNode cur=head;cur!=null;cur=cur.next){ ..原创 2021-03-05 13:31:06 · 56 阅读 · 0 评论 -
逆置链表
思路链表为空或者链表只有一个节点,无需逆置,直接返回head即可代码class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { this.val = val; } }public class Test2 { //创建一个链表 public static ListNode init(){ ListNode node1=new.原创 2021-02-22 11:27:18 · 92 阅读 · 0 评论 -
删除链表中所有指定值的节点
思路链表为空,则返回null 定义两个节点,待删节点和待删节点的前一个节点 如下图,每种颜色代表不同步骤的操作我们相当于是从第二个节点开始判断的,所以最后还要判断一下第一个节点是否满足删除条件,在上面链表中,显然满足,所以让head指向第一个节点的下一个节点,最终返回head,即删除了第一个第一个节点代码class ListNode { int val; ListNode next; ListNode(int val) { this.val = v.原创 2021-02-19 21:42:51 · 499 阅读 · 0 评论 -
空间复杂度
基本概念空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。 空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。示例1)计算bubbleSort的空间复杂度?void bubbleSort(int[] array) { for (int end = array.length; end > 0; end--) { boolean sor原创 2021-01-29 15:26:51 · 90 阅读 · 1 评论 -
时间复杂度
时间复杂度用来衡量一个算法的运行速度,也就是程序运行的快慢 算法中的基本操作的执行次数,称为时间复杂度。 其中基本操作可能是++,可能是赋值,也可能是读取,也可能是打印... 基本操作的执行次数,不是精确的,使用大O渐近法表示,保留最高阶项,同时去掉系数,得到一个衡量时间复杂度的“近似值”示例1)计算func2的时间复杂度?void func2(int N) { int count = 0; for (int k = 0; k < 2 * N ; k++) {原创 2021-01-28 20:29:15 · 193 阅读 · 0 评论