数据结构与算法
文章平均质量分 77
北在哪
这个作者很懒,什么都没留下…
展开
-
骑士周游回溯算法
主要思想:深度优先遍历+回溯+贪心。从初始位置startPoint开始,获取下一步能到达的所有位置,将它们添加到集合ArrayList< Point >中,根据它们下一步所能到达的位置的个数k对ArrayList< Point >中所有位置进行非递减排序,优先对k较小的位置进行遍历,若此路不通,则回溯。马踏棋盘游戏中马能够走的8个位置如下图所示:本次使用的实例:代码实现:package DataStructure;import java.awt.*;import j原创 2020-09-08 21:03:27 · 457 阅读 · 0 评论 -
最短路径 | Floyd算法(基本)
主要思想:将图中每个顶点Vk依次作为中转顶点,比较每个顶点Vi直接到达其余各个顶点Vj的距离dis[ij]与通过中转顶点Vk再到达其余各个顶点Vj的距离dis[ik]+dis[kj],若dis[ik]+dis[kj] < dis[ij],则将dis[ij]更新为dis[ik]+dis[kj] 。经过三次嵌套循环,可获得任意两个顶点之间的最短路径(而Dijkstra算法只能获得指定顶点到其余顶点的最短路径)。代码实现:package DataStructure;import java.util.原创 2020-09-05 16:15:01 · 180 阅读 · 0 评论 -
最短路径 | 深入浅出Dijkstra算法
写在前面:上次我们介绍了神奇的只有五行的 Floyd-Warshall 最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最短路”。这次来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”。例如求下图中的 1 号顶点到 2、3、4、5、6 号顶点的最短路径。Dijkstra算法与 Floyd-Warshall 算法一样,这里仍然使用二维数组 e 来存储顶点之间边的关系,初始值如下。我们还需要用一个一维数组 dis 来存储 1 号顶点到其余各个顶点的初始路程,我们可转载 2020-09-04 21:44:38 · 260 阅读 · 0 评论 -
普里姆算法
代码实现:package DataStructure;public class PrimDemo { public static void main(String[] args) { Graph2 graph = new Graph2(7); String[] vertexS = {"A", "B", "C", "D", "E", "F", "G"}; for (String vertex : vertexS) { ...原创 2020-08-17 21:44:31 · 129 阅读 · 0 评论 -
贪心算法
提出问题:使用贪心算法解决该问题:主要思路:遍历所有广播电台,找到一个覆盖了最多未覆盖地区的电台;将这个电台加入一个集合中(如ArrayList),并将该电台已覆盖的地区从未覆盖地区集中删掉;重复1、2步,直至无未覆盖地区。代码实现:package DataStructure;import java.util.ArrayList;import java.util.HashMap;import java.util.HashSet;import java.util.List;p原创 2020-08-17 09:54:04 · 90 阅读 · 0 评论 -
KMP算法
Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP算法”,常用于在一个文本串S内查找一个模式串P 的出现位置,这个算法由Donald Knuth、Vaughan Pratt、James H. Morris三人于1977年联合发表,故取这3人的姓氏命名此算法。......原创 2020-08-16 17:45:13 · 181 阅读 · 0 评论 -
动态规划算法解决背包问题
什么是背包问题?问题描述:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。如果限定每种物品只能选择0个或1个,则问题称为0-1背包问题。如果限定物品最多只能选择j个(j = 0, 1, 2…),则问题称为有界背包问题。如果不限定每种物品的数量,则问题称为无界背包问题。使用动态规划解决0-1背包问题:假如我们有以下三个物品,需要放入容量为4的背包里,使得总价格最大:我们先使用一个数组items[ ]储存物品名字,数组w[ ]储存物品的重原创 2020-08-15 13:07:27 · 472 阅读 · 0 评论 -
分治算法解决汉诺塔问题
汉诺塔问题:相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。package DataStructure;public class HanoiTowerDemo { public stati原创 2020-08-14 17:16:02 · 172 阅读 · 0 评论 -
图的广度优先遍历(BFS)
图的广度优先遍历基本思想:横向搜索,遍历完一个顶点的所有邻接顶点后,再遍历其他顶点的邻接顶点。需要使用一个队列,用来保存被首次访问的顶点,然后按照顺序弹出进行遍历。举一个具体例子:对上图进行BFS:首先访问初始顶点A,将其加入队列判断队列是否为空,若不为空,则弹出队尾一个顶点,遍历该顶点的所有邻接顶点在上述遍历过程中,如果有首次访问的邻接顶点,需要将其加入队列所有邻接顶点遍历完后,再次判断队列是否为空,若不为空,重复1~4步骤;若为空,则程序结束。package DataStru原创 2020-08-14 15:53:19 · 373 阅读 · 0 评论 -
图的深度优先遍历(DFS)
图的深度优先遍历基本思想:访问指定的起始顶点;若当前访问的顶点的邻接顶点有未被访问的,首先选第一个访问,其次第二个…;反之,退回到最近访问过的顶点,查看当前顶点还有没有其他未访问的邻接顶点,访问之;直到与起始顶点直接或间接相通的全部顶点都访问完毕;若此时图中尚有顶点未被访问(不连通点),则遍历所有顶点作为起始顶点并访问之,转 2; 反之,遍历结束。算法步骤:对于上图来说,我们可以将图中各个顶点的连接关系用树来表示(以A为初始顶点):首先访问A,标记为已访问:然后访问A的第一个邻接顶点B原创 2020-08-14 12:31:20 · 456 阅读 · 0 评论 -
图(Graph)
与线性表和树不同,图可以表示多对多的关系。图的常用概念有:顶点(vertex)边(edge)路径无向图有向图带权图无向图:有向图和带权图:图的表示方式:图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表)邻接矩阵:邻接矩阵是表示图中顶点之间相邻关系的矩阵,n个顶点的图可以用n x n二维数组来表示。下图有6个顶点,用6 x 6二维数组表示,其中1表示直接相连,0表示不直接相连:邻接表:邻接矩阵需要为每个顶点都分配n个边的空间,不管边是否存在,这样会浪费一原创 2020-08-13 20:12:25 · 496 阅读 · 0 评论 -
多叉树(2-3树、B树、B+树、B*树)
二叉树存在的问题:节点过多会造成:①构造树耗时长 ②查询代价高多叉树:拥有2个子节点的节点称为2节点,拥有3个子节点的节点称为3节点。2-3树:B树:B+树:相当于将单链表分为许多段,所有数据都存放在叶子节点,非叶子节点存放索引。B*树:...原创 2020-08-13 16:09:46 · 214 阅读 · 0 评论 -
AVL 自平衡二叉树
自平衡二叉树:平衡二叉树也叫平衡二叉搜索树(self-balancing binary search tree),又被称为AVL树,可以保证查询效率较高。平衡二叉树的左右两颗子树的高度差的绝对值不超过1,并且左右子树都是平衡二叉树。如下图中:1,2为平衡二叉树,3则不是。以下由浅入深讨论如何将一棵树转换为AVL树:首先简单讨论右子树高度 - 左子树高度 > 1 的情况:左子树高度 - 右子树高度 > 1 的情况:我们可以看到,前面的两个数列,进行单旋转(即一次旋转)就可以将非平衡原创 2020-08-13 11:46:06 · 154 阅读 · 0 评论 -
BST 二叉排序树(Binary Sort Tree)
二叉排序树介绍:对于二叉排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大。如下图所示:二叉排序树插入节点可以用递归实现,本次代码实现默认将大于等于当前节点值的节点放置在当前节点的右子节点。使用中序遍历可以顺序输出二叉排序树中的值。相比于插入节点,二叉排序树的删除情况比较复杂,有下面三种情况需要考虑删除叶子节点(如上图的:2,5,9,12)删除只有一个子树的节点(如:1)删除有两颗子树的节点(如:7,3,10)第一种情况:删除叶子节点思路:原创 2020-08-12 21:28:27 · 177 阅读 · 0 评论 -
堆排序
理解堆排序之前,我们首先需要了解顺序存储二叉树的概念:假设存在一个数组array,我们从下标0开始,按下标顺序将其按照完全二叉树的形式排列,这样构成的二叉树就称为顺序存储二叉树。顺序存储二叉树的节点array[ i ]的左子节点为array[ 2 * i + 1 ],右子节点为array[ 2 * i + 2 ]。下面进入正题:堆其实就是具有特殊性质的完全二叉树:若每个节点的值都大于或等于其左右节点的值,则称为大顶堆;若每个节点的值都小于或等于其左右节点的值,则称为小顶堆。如果用数组来表示一个大顶堆原创 2020-08-11 11:05:18 · 118 阅读 · 0 评论 -
中序线索化二叉树并遍历
线索化二叉树① n个结点的二叉树有n+1个空指针域,上图有6个结点,所以它的空指针域有7个。我们可以利用二叉树中的空指针域,存放指向当前结点在某种遍历次序下的前驱和后继结点的指针,这种附加的指针称为“线索”。② 这种加上了线索的二叉树称为线索二叉树。根据遍历次序的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。③ 前驱、后继结点是相对于遍历次序来说的,遍历次序在当前结点前一位的结点称为前驱结点,后一位称为后继结点。package DataStructure;..原创 2020-08-10 17:37:35 · 1623 阅读 · 0 评论 -
二叉树的前、中、后序遍历
前序:根左右中序:左根右后序:左右根前序遍历:124563中序遍历:564213后序遍历:564231package DataStructure;public class BinaryTreeDemo { public static void main(String[] args) { Hero root = new Hero(1, "宋江"); root.left = new Hero(2,"卢俊义"); root.right =原创 2020-08-09 18:08:19 · 108 阅读 · 0 评论 -
斐波那契查找
要点:斐波那契查找的中间结点不再是中间或者插值得到,而是位于黄金分割点附近,即mid = begin + F[k - 1] - 1。其中F[ ]表示斐波那契数列。对F[k - 1] - 1的理解:由斐波那契数列的性质F[k] = F[k - 1] + F[k - 2] ,可以得到F[k] - 1 = F[k - 1] - 1 + F[k - 2] - 1 + 1。该式说明只要顺序数列的长度为F[k] - 1,就可以将该数列分成F[k - 1] - 1和F[k - 2] - 1的两段,中间点则为F[k原创 2020-08-09 10:54:40 · 130 阅读 · 0 评论 -
插值查找
插值查找是二分查找的改良版,可以减少递归调用的次数,适用于数据分布比较均匀的序列。它采用自适应的方式确定mid值:二分查找:mid = (begin + last) / 2 = begin + 0.5 * (last - begin)插值查找:mid = begin + (i - arr[begin]) / (arr[last] - arr[begin]) * (last - begin)二分查找中的0.5替换成了(i - arr[begin]) / (arr[last] - arr[begin]),原创 2020-08-09 09:08:27 · 152 阅读 · 0 评论 -
二分查找
package DataStructure;import java.util.ArrayList;import java.util.Arrays;public class ErFenSearch { public static void main(String[] args) { int[] arr = {9, 2, 2, 8, 2, 3, 4, 2, 1}; ChooseSort.sort(arr); System.out.println(原创 2020-08-08 16:52:08 · 80 阅读 · 0 评论 -
基数排序
要点:按照位数排序,从个位数开始,位数不够则补零,将数字放置在其位数相对应的桶中,然后再从桶中依次取出排序,如此循环直到最高位,循环次数由数组中最大的绝对值的位数决定。package DataStructure;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Arrays;import java.util.Date;import java.util.List;public class原创 2020-08-08 15:23:59 · 104 阅读 · 0 评论 -
归并排序
要点:https://zhuanlan.zhihu.com/p/36075856package DataStructure;import java.util.Arrays;public class MergeSort { public static void main(String[] args) { int[] arr = {55, 48, 6, 24, 88, 1230, 558}; int[] temp = new int[arr.length];原创 2020-08-07 18:37:36 · 103 阅读 · 0 评论 -
快速排序
要点:length/2取得序列的中轴值pivot,将所有比pivot小的值移到pivot左边,大的值移到右边;完成后,对pivot左右两边的数据都重新取中轴,重复上述操作(用递归实现)。package DataStructure;import java.text.SimpleDateFormat;import java.util.Arrays;import java.util.Date;public class QuickSort { public static void main(S原创 2020-08-07 11:07:58 · 71 阅读 · 0 评论 -
希尔排序
希尔排序是插入排序的改良版,可以解决移位次数较多带来的效率低下问题。要点:对序列(长度为length)进行多次分组,每次分组后都对不同组的数据进行插入排序,分组数量由步长决定,而第一次分组的步长由length / 2取整所得,下一次分组的步长由上次步长 / 2取整所得,当步长为0时,排序完成。比如说length=10,10/2=5,那么第一次分组的步长为5,所以分为5组,对每一组进行排序;5/2=2,所以第二次分组的步长为2,分成了2组,对每一组进行排序;2/2=1,步长为1,分成一组排序;1/2=0,步原创 2020-08-06 21:36:16 · 66 阅读 · 0 评论 -
插入排序
要点:将一个序列(长度为length)分为有序表和无序表,每次取无序表中一个数插入到有序表中,使其始终有序,总共需要执行length-1次。package DataStructure;import java.text.SimpleDateFormat;import java.util.Arrays;import java.util.Date;public class InsertSort { public static void main(String[] args) {//原创 2020-08-04 17:21:51 · 88 阅读 · 0 评论 -
选择排序
要点:每次选出最小的值放置在序列最左边,然后对剩下的序列重复该操作,共执行length-1次。import java.text.SimpleDateFormat;import java.util.Arrays;import java.util.Date;public class ChooseSort { public static void main(String[] args) {// int[] arr = {0, 55, 48, 6, 24, 88, 1230, 55原创 2020-08-04 16:25:36 · 86 阅读 · 0 评论 -
冒泡排序
import java.text.SimpleDateFormat;import java.util.Arrays;import java.util.Date;public class MaoPao { public static void main(String[] args) {// int[] arr = {55, 48, 6, 24, 88, 1230, 558};// sort(arr);// // sortEnhance(arr);原创 2020-08-04 10:48:07 · 86 阅读 · 0 评论 -
递归回溯解决八皇后问题
public class Queen8Demo {public static final int MAX = 8; // 8个皇后public int[] array = new int[8]; // 使用一个一位数组保存皇后放置的位置,数组的索引代表皇后所在行,值代表所在列。public int count = 0; // 统计解的个数public static void main(String[] args) { Queen8Demo queen = new Queen8Demo();原创 2020-07-25 17:22:10 · 78 阅读 · 0 评论 -
使用递归回溯解决迷宫问题
/*目的:从左上角走到右下角。地图用数组表示,0表示可走,1表示墙,2表示已走过(不能再走),3表示已走过但走不通。策略:向下→向右→向上→向左初始地图:1 1 1 1 1 1 11 0 0 0 0 0 11 0 0 0 0 0 11 1 1 0 1 0 11 0 0 1 0 0 11 0 0 0 0 0 11 0 0 0 0 0 11 1 1 1 1 1 1运行结果:1 1 1 1 1 1 11 2 0 0 0 0 11 2 2 2 2 2 11 1 1 3 1 2 1原创 2020-07-24 22:43:39 · 108 阅读 · 0 评论 -
中缀转后缀表达式
中缀表达式转后缀表达式步骤:1.初始化两个栈:储存运算符的栈s1和储存中间结果的栈s2;2.从左至右扫描中缀表达式;3.遇到操作数时,将其压入s2;4.遇到运算符时,比较其与s1栈顶运算符的优先级:1)如果s1为空,或栈顶运算符为左括号“(”,或优先级比栈顶运算符的高,则直接将此运算符压入s1;2)否则,将s1栈顶的运算符弹出并压入到s2中,再次与新的s1栈顶运算符相比较。5.遇到括号时:1)如果是左括号“(”,则直接压入s1;2)如果是右括号“)”,则依次弹出s1栈顶运算符并压入s2,直原创 2020-07-22 19:23:15 · 139 阅读 · 0 评论 -
数组模拟环形队列
主要思想:采用双指针,指针front永远指向队列第一个元素,指针rear永远指向队列最后一个元素位置+1;front与rear之间约定预留一个位置,即若初始化数组容量为10(maxSize),则有效存储位只有9个。使用公式:(rear + maxSize - front) % maxSize 可求出队列中元素个数。public class ArrayQueueDemo{ public static void main(String[] args) { ArrayQueue q = new Arra原创 2020-07-10 20:39:38 · 121 阅读 · 0 评论