数据结构与算法(java)
简述
在编程过程中,通常会遇到的一个问题就是,性能瓶颈。很多时候考虑的都是怎么去做横向扩展,但偏偏忽略掉了最基本的问题就是系统是否真的已经达到了瓶颈?
性能瓶颈通常的表象是资源消耗过多外部处理系统的性能不足;或者资源消耗不多但程序的响应速度却仍达不到要求。
而调优的方式就是 寻找过度消耗资源的代码 和 寻找未充分使用资源但程序执行慢的原因和代码。 基础决定高度 就拿汽车来比较,通常不懂变速箱、发动机的原理但也是能开车,同样一个不懂数据结构和算法的人也能编程。很多人觉得基本的数据结构及操作已经在高级语言中封装,都可以直接调用库函数,那么到底有没有必要好好学习数据结构?
数据结构+算法=程序
通常在程序中,遇到一个实际问题,充分利用数据结构,将数据及其之间的关系有效地存储在计算机中,然后选择合适的算法策略,并用程序高效实现,这才是提高程序性能的主要方式。
- 如何有效地存储数据,不同的数据结构产生什么样的算法复杂性,有没有更好的存储方法提高算法的效率?
如果没有具备这块相应的知识,怎么完成上述的实现?如果脱离了原有的调用,怎么完成程序的高效实现?而所有的应用实现都依赖于基础,基础就是数据结构和算法。了解这块,才能做到无惧任何技术的演变。所有说基础决定高度!
基本的概念
数据结构表示数据在计算机中的存储和组织形式,主要描述数据元素之间和位置关系等。选择适当的数据结构可以提高计算机程序的运行效率(时间复杂度)和存储效率(空间复杂度)。
数据结构的三种层次
:
- 逻辑结构--抽象层: 主要描述的是数据元素之间的逻辑关系
集合结构(集)
: 所有的元素都属于一个总体,除了同属于一个集合外没有其他关系。集合结构不强调元素之间的任何关联性。线性结构(表)
: 数据元素之间具有一对一的前后关系。结构中必须存在唯一的首元素和唯一的尾元素。树形结构(树)
: 数据元素之间一对多的关系网状结构(图)
: 图状结构或网状结构 结构中的数据元素之间存在多对多的关系
- 物理结构--存储层: 主要描述的是数据元素之间的位置关系
顺序结构
: 顺序结构就是使用一组连续的存储单元依次存储逻辑上相邻的各个元素
优点
: 只需要申请存放数据本身的内存空间即可,支持下标访问,也可以实现随机访问。
缺点
: 必须静态分配连续空间,内存空间的利用率比较低。插入或删除可能需要移动大量元素,效率比较低链式结构
: 链式存储结构不使用连续的存储空间存放结构的元素,而是为每一个元素构造一个节点。节点中除了存放数据本身以外,还需要存放指向下一个节点的指针。
优点
: 不采用连续的存储空间导致内存空间利用率比较高,克服顺序存储结构中预知元素个数的缺点 插入或删除元素时,不需要移动大量的元素。
缺点
: 需要额外的空间来表达数据之间的逻辑关系, 不支持下标访问和随机访问。索引结构
: 除建立存储节点信息外,还建立附加的索引表来标节点的地址。索引表由若干索引项组成。
优点
: 是用节点的索引号来确定结点存储地址,检索速度块
`缺点: 增加了附加的索引表,会占用较多的存储空间。散列结构
: 由节点的关键码值决定节点的存储地址。散列技术除了可以用于查找外,还可以用于存储。
优点
: 散列是数组存储方式的一种发展,采用存储数组中内容的部分元素作为映射函数的输入,映射函数的输出就是存储数据的位置, 相比数组,散列的数据访问速度要高于数组
缺点
: 不支持排序,一般比用线性表存储需要更多的空间,并且记录的关键字不能重复。
- 运算结构--实现层: 主要描述的是如何实现数据结构
- 分配资源,建立结构,释放资源
- 插入和删除
- 获取和遍历
- 修改和排序
每种逻辑结构采用何种物理结构来实现,并没有具体的规定。当一个结构,在逻辑结构中只有一种定义,而在物理结构中却有两种选择,那么这个结构就属于逻辑结构;
数据结构比较
常用的数据结构:
数据结构选择:
O符号
O在算法当中表述的是时间复杂度,它在分析算法复杂性的方面非常有用。常见的有:
O(1)
:最低的复杂度,无论数据量大小,耗时都不变,都可以在一次计算后获得。哈希算法就是典型的O(1)O(n)
:线性,n表示数据的量,当量增大,耗时也增大,常见有遍历算法O(n²)
:平方,表示耗时是n的平方倍,当看到循环嵌循环的时候,基本上这个算法就是平方级的,如:冒泡排序等O(log n)
:对数,通常ax=n,那么数x叫做以a为底n的对数,也就是x=logan,这里是a通常是2,如:数量增大8倍,耗时只增加了3倍,二分查找就是对数级的算法,每次剔除一半O(n log n)
:线性对数,就是n乘以log n,按照上面说的数据增大8倍,耗时就是8*3=24倍,归并排序就是线性对数级的算法
Array
在Java中,数组是用来存放同一种数据类型的集合,注意只能存放同一种数据类型。
//只声明了类型和长度
数据类型 [] 数组名称 = new 数据类型[数组长度];
//声明了类型,初始化赋值,大小由元素个数决定
数据类型 [] 数组名称 = {数组元素1,数组元素2,......}
复制代码
大小固定,不能动态扩展(初始化给大了,浪费;给小了,不够用),插入快,删除和查找慢
模拟实现
public class Array {private int[] intArray;private int elems;private int length;public Array(int max) {length = max;intArray = new int[max];elems = 0;}/*** 添加* @param value*/public void add(int value){if(elems == length){System.out.println("error");return;}intArray[elems] = value;elems++;}/*** 查找* @param searchKey* @return*/public int find(int searchKey){int i;for(i = 0; i < elems; i++){if(intArray[i] == searchKey)break;}if(i == elems){return -1;}return i;}/*** 删除* @param value* @return*/public boolean delete(int value){int i = find(value);if(i == -1){return false;}for (int j = i; j < elems-1; j++) {//后面的数据往前移intArray[j] = intArray[j + 1];}elems--;return true;}/*** 更新* @param oldValue* @param newValue* @return*/public boolean update(int oldValue,int newValue){int i = find(oldValue);if(i == -1){return false;}intArray[i] = newValue;return true;}/*** 显示所有*/public void display(){for(int i = 0 ; i < elems ; i++){System.out.print(intArray[i]+" ");}System.out.print("\n");}/*** 冒泡排序* 每趟冒出一个最大数/最小数* 每次运行数量:总数量-运行的趟数(已冒出)*/public void bubbleSort(){for(int i = 0; i < elems-1; i++){//排序趟数 n-1次就行了System.out.println("第"+(i+1)+"趟:");for(int j = 0; j < elems-i-1; j++){//每趟次数 (n-i) -1是防止下标越界,后面赋值用到了+1if(intArray[j] > intArray[j+1]){ //控制按大冒泡还是按小冒泡int temp = intArray[j];intArray[j] = intArray[j+1];intArray[j+1] = temp;}display();}}}/**** 选择排序* 每趟选择一个最大数/最小数* 每次运行数量:总数量-运行的趟数(已选出)*/public void selectSort(){for(int i = 0; i < elems-1; i++) {//排序趟数 n-1次就行了int min = i;for(int j = i+1; j < elems; j++){ //排序次数 每趟选择一个数出来,-1次if(intArray[j] < intArray[min]){min = j;}}if(i != min ){int temp = intArray[i];intArray[i] = intArray[min];intArray[min] = temp;}display();}}/*** 插入排序* 每趟选择一个待插入的数* 每次运行把待插入的数放在比它大/小后面*/public void insertSort(){int j;for(int i = 1; i < elems; i++){int temp = intArray[i];j = i;while (j > 0 && temp < intArray[j-1]){intArray[j] = intArray[j-1];j--;}intArray[j] = temp;}display();}public static void main(String[] args) {Array array = new Array(10);array.add(6);array.add(3);array.add(8);array.add(2);array.add(11);array.add(5);array.add(7);array.add(4);array.add(9);array.add(10);
// array.bubbleSort();
// array.selectSort();array.insertSort();
// array.display();
// System.out.println(array.find(4));
// System.out.println(array.delete(1));
// array.display();
// System.out.println(array.update(2,6));
// array.display();}
}
复制代码
Stack
- 栈(stack)又称为堆栈或堆叠,栈作为一种数据结构,它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶
- java中Stack是Vector的一个子类,只定义了默认构造函数,用来创建一个空栈。
- 栈是元素的集合,其包含了两个基本操作:push 操作可以用于将元素压入栈,pop 操作可以将栈顶元素移除。
- 遵循后入先出(LIFO)原则。
- 时间复杂度:
- 索引:
O(n)
- 搜索:
O(n)
- 插入:
O(1)
- 移除:
O(1)
Stack()
复制代码
模拟实现
public class Stack {//小贴士:通常可以利用栈实现字符串逆序,还可以利用栈判断分隔符是否匹配,如<a[b{c}]>,可以正进反出,栈为空则成功。/**基于数组实现的顺序栈,连续存储的线性实现,需要初始化容量**///固定数据类型//private int[] array;//动态数据类型private Object[] objArray;private int maxSize;private int top;public Stack() {}public Stack(int maxSize) {if(maxSize > 0){objArray = new Object[maxSize];this.maxSize = maxSize;top = -1;}else{throw new RuntimeException("初始化大小错误:maxSize=" + maxSize);}}/*** 入栈* @param obj*/public void objPush(Object obj){//扩容grow();//++在前表示先运算再赋值,优先级高,在后表示先赋值再运算,优先级低objArray[++top] = obj;}/*** 出栈* @return*/public Object objPop(){Object obj = peekTop();//声明原顶栈可以回收空间(GC)objArray[top--] = null;return obj;}/*** 查看栈顶* @return*/public Object peekTop(){if(top != -1){return objArray[top];}else{throw new RuntimeException("stack is null");}}/*** 动态扩容*/public void grow(){// << 左移运算符,1表示乘以2的1次方if(top == maxSize-1){maxSize = maxSize<<1;objArray = Arrays.copyOf(objArray,maxSize);}}/**基于链式存储,不连续存储的非线性实现**/private class Node<Object>{private Object data;private Node next;public Node(Object data, Node next) {this.data = data;this.next = next;}}private Node nodeTop;private int size;public void nodePush(Object obj){//栈顶指向新元素,新元素的next指向原栈顶元素nodeTop = new Node(obj,nodeTop);size++;}public Object nodePop(){Node old = nodeTop;//声明原顶栈可以回收空间(GC)old.next = null;//栈顶指向下一个元素nodeTop = nodeTop.next;size--;return old.data;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("[ ");for(Node<Object> node = nodeTop; node != null; node = node.next){sb.append(node.data.toString() + " ");}return sb.toString()+"]";}public static void main(String[] args) {
// Stack stack = new Stack(1);
// stack.objPush("abc");
// stack.objPush(123);
// stack.objPush("de");
// stack.objPush("cd");
// stack.objPush("er");
// stack.objPush("hello");
// stack.objPush(666);
// stack.objPush(545);
// stack.objPush("word");
// while (stack.top != -1){// System.out.println(stack.objPop());
// }
// System.out.println(stack.peekTop());Stack stack = new Stack();stack.nodePush("111");stack.nodePush("222");stack.nodePush("aaa");stack.nodePush("bbb");System.out.println(stack);while (stack.size > 1)System.out.println(stack.nodePop());System.out.println(stack);}
}
复制代码
Queue
- 队列是元素的集合,其包含了两个基本操作:enqueue 操作可以用于将元素插入到队列中,而 dequeue 操作则是将元素从队列中移除。
- 遵循先入先出原则 (FIFO)。
- 时间复杂度:
- 索引:
O(n)
- 搜索:
O(n)
- 插入:
O(1)
- 移除:
O(1)
public class Queue {/**** 1.单向队列(Queue):只能在一端插入数据,另一端删除数据。* 2.双向队列(Deque):每一端都可以进行插入数据和删除数据操作。** 与栈不同的是,队列中的数据不总是从数组的0下标开始的* 选择的做法是移动队头和队尾的指针。* 为了避免队列不满却不能插入新的数据,我们可以让队尾指针绕回到数组开始的位置,这也称为“循环队列”。* */// 单向循环队列,顺序存储结构实现private Object[] objQueue;//队列大小private int maxSize;//顶部private int top;//底部private int bottom;//实际元素private int item;public Queue(int size) {maxSize = size;objQueue = new Object[maxSize];top = 0;bottom = -1;item = 0;}/*** 入队* @param obj*/public void add(Object obj){if(item == maxSize){throw new RuntimeException(obj+" add error, queue is full");}//循环队列,首尾结合,下标控制队首和队尾位置if(bottom == maxSize-1){bottom = -1;}objQueue[++bottom] = obj;item++;}/*** 出对* @return*/public Object out(){if(item == 0){throw new RuntimeException("queue is null");}Object obj = objQueue[top];//声明原顶栈可以回收空间(GC)objQueue[top] = null;top++;//重置下标if(top == maxSize){top = 0;}item--;return obj;}//链式存储结构实现private class NodeQueue<Object>{private Object data;private NodeQueue next;public NodeQueue(Object data, NodeQueue next) {this.data = data;this.next = next;}}//队列头 出private NodeQueue queueTop;//队列尾 进private NodeQueue queueBottom;//队列大小private int size;public Queue() {queueTop = null;queueBottom = null;size = 0;}/*** 入队* @param obj*/public void addNodeQueue(Object obj){if(size == 0){queueTop = new NodeQueue(obj,null);//指向同一存储地址queueBottom = queueTop;}else{NodeQueue<Object> nodeQueue = new NodeQueue(obj,null);//让尾节点的next指向新增的节点queueBottom.next = nodeQueue;//以新节点作为尾节点queueBottom = nodeQueue;}size ++;}/*** 出队* @return*/public Object removeNodeQueue(){if(size == 0){throw new RuntimeException("queue is null");}NodeQueue nodeQueue = queueTop;queueTop = queueTop.next;//声明原队列头next可以回收空间(GC)nodeQueue.next = null;size--;return nodeQueue.data;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("{ ");for(NodeQueue nodeQueue = queueTop ; nodeQueue != null ; nodeQueue = nodeQueue.next){sb.append(nodeQueue.data.toString()+" ");}return sb.toString()+"}";}public static void main(String[] args) {Queue queue = new Queue();queue.addNodeQueue("123");queue.addNodeQueue("abc");queue.addNodeQueue("ddd");System.out.println(queue);queue.removeNodeQueue();System.out.println(queue);queue.removeNodeQueue();queue.removeNodeQueue();System.out.println(queue);}
}
复制代码
Linked List
- 链表即是由节点(Node)组成的线性集合,每个节点可以利用指针指向其他节点。它是一种包含了多个节点的、能够用于表示序列的数据结构。
单向链表
: 链表中的节点仅指向下一个节点,并且最后一个节点指向空。双向链表
: 其中每个节点具有两个指针 p、n,使得 p 指向先前节点并且 n 指向下一个节点;最后一个节点的 n 指针指向 null。循环链表
:每个节点指向下一个节点并且最后一个节点指向第一个节点的链表。- 时间复杂度:
- 索引:
O(n)
- 搜索:
O(n)
- 插入:
O(1)
- 移除:
O(1)
- 索引:
public class LinkedList {/**** 链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接("links")*/private Node head; //链表头private Node tail; //链表尾private int size; //节点数/*** 双端链表*/public class Node{private Object data;private Node prev; //上一个private Node next; //下一个public Node(Object data) {this.data = data;}}public LinkedList() {this.head = null;this.tail = null;this.size = 0;}/*** 向链表头添加数据* @param object*/public void addHead(Object object){Node node = new Node(object);if(size == 0){head = node;tail = node;size++;}else{head.prev = node;node.next = head;head = node;size++;}}/*** 删除头*/public void deleteHead(){//头部指向下一个,prev值为null则说明是链表的头部if(size != 0){head.prev = null;head = head.next;size--;}}/***向链表尾添加数据* @param object*/public void addTail(Object object){Node node = new Node(object);if(size == 0){head = node;tail = node;size++;}else{node.prev = tail;tail.next = node;tail = node;size++;}}/*** 删除尾部*/public void deleteTail(){//尾部指向上一个,next值为null则说明是链表的尾部if(size != 0){tail.next = null;tail = tail.prev;size--;}}/*** 显示数据*/public void display(){Node node = head;while (size > 0){System.out.print("["+node.data+"->");node = node.next;size--;}}public static void main(String[] args) {LinkedList linkedList = new LinkedList();linkedList.addHead("123");
// linkedList.addHead("abc");
// linkedList.addHead("%$$");
// linkedList.addTail("+_+");
// linkedList.addTail("hello");linkedList.addTail("word");linkedList.deleteHead();linkedList.deleteTail();linkedList.display();}
}
复制代码
Binary Tree
二叉树(由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成) 二叉树即是每个节点最多包含左子节点与右子节点这两个节点的树形数据结构。
满二叉树
: 树中的每个节点仅包含 0 或 2 个节点。完美二叉树(Perfect Binary Tree)
: 二叉树中的每个叶节点都拥有两个子节点,并且具有相同的高度。完全二叉树
: 除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。
红黑树(每节点五元素,颜色(如果一个节点是红的,则它的两个儿子都是黑的)、键值、左子节点、右字节的、父节点)
Heap
- 堆(也被称为优先队列(队列+排序规则),图一最大堆,图二最小堆)
- 堆是一种特殊的基于树的满足某些特性的数据结构,整个堆中的所有父子节点的键值都会满足相同的排序条件。堆更准确地可以分为最大堆与最小堆,在最大堆中,父节点的键值永远大于或者等于子节点的值,并且整个堆中的最大值存储于根节点;而最小堆中,父节点的键值永远小于或者等于其子节点的键值,并且整个堆中的最小值存储于根节点。
- 时间复杂度:
- 访问最大值 / 最小值:
O(1)
- 插入:
O(log(n))
- 移除最大值 / 最小值:
O(log(n))
- 访问最大值 / 最小值:
Hashing
- 哈希能够将任意长度的数据映射到固定长度的数据。哈希函数返回的即是哈希值,如果两个不同的键得到相同的哈希值,即将这种现象称为碰撞。
- Hash Map: Hash Map 是一种能够建立起键与值之间关系的数据结构,Hash Map 能够使用哈希函数将键转化为桶或者槽中的下标,从而优化对于目标值的搜索速度。
- 碰撞解决
链地址法(Separate Chaining)
: 链地址法中,每个桶是相互独立的,包含了一系列索引的列表。搜索操作的时间复杂度即是搜索桶的时间(固定时间)与遍历列表的时间之和。开地址法(Open Addressing)
: 在开地址法中,当插入新值时,会判断该值对应的哈希桶是否存在,如果存在则根据某种算法依次选择下一个可能的位置,直到找到一个尚未被占用的地址。所谓开地址法也是指某个元素的位置并不永远由其哈希值决定。
Graph
- 图是一种数据元素间为多对多关系的数据结构,加上一组基本操作构成的抽象数据类型。
无向图(Undirected Graph)
: 无向图具有对称的邻接矩阵,因此如果存在某条从节点 u 到节点 v 的边,反之从 v 到 u 的边也存在。有向图(Directed Graph)
: 有向图的邻接矩阵是非对称的,即如果存在从 u 到 v 的边并不意味着一定存在从 v 到 u 的边。
算法
排序
快速排序
- 稳定: 否
- 时间复杂度:
- 最优时间:
O(nlog(n))
- 最坏时间:
O(n^2)
- 平均时间:
O(nlog(n))
- 最优时间:
归并排序
- 归并排序是典型的分治算法,它不断地将某个数组分为两个部分,分别对左子数组与右子数组进行排序,然后将两个数组合并为新的有序数组。
- 稳定: 是
- 时间复杂度:
- 最优时间:
O(nlog(n))
- 最坏时间:
O(nlog(n))
- 平均时间:
O(nlog(n))
- 最优时间:
桶排序
- 桶排序将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。
- 时间复杂度:
- 最优时间:
Ω(n + k)
- 最坏时间:
O(n^2)
- 平均时间:
Θ(n + k)
- 最优时间:
基数排序
- 基数排序类似于桶排序,将数组分割到有限数目的桶中;不过其在分割之后并没有让每个桶单独地进行排序,而是直接进行了合并操作。
- 时间复杂度:
- 最优时间:
Ω(nk)
- 最坏时间:
O(nk)
- 平均时间:
Θ(nk)
- 最优时间:
图算法
深度优先搜索
- 深度优先算法是一种优先遍历子节点而不是回溯的算法。
- 时间复杂度:
O(|V| + |E|)
广度优先搜索
- 广度优先搜索是优先遍历邻居节点而不是子节点的图遍历算法。
- 时间复杂度:
O(|V| + |E|)
拓扑排序
- 拓扑排序是对于有向图节点的线性排序,如果存在某条从 u 到 v 的边,则认为 u 的下标先于 v。
- 时间复杂度:
O(|V| + |E|)
Dijkstra 算法
- Dijkstra 算法 用于计算有向图中单源最短路径问题。
- 时间复杂度:
O(|V|^2)
Bellman-Ford 算法
- **
Bellman-Ford 算法
**是在带权图中计算从单一源点出发到其他节点的最短路径的算法。 - 尽管算法复杂度大于 Dijkstra 算法,但是它适用于包含了负值边的图。
- 时间复杂度:
- 最优时间:
O(|E|)
- 最坏时间:
O(|V||E|)
- 最优时间:
Floyd-Warshall 算法
Floyd-Warshall 算法
能够用于在无环带权图中寻找任意节点的最短路径。- 时间复杂度:
- 最优时间:
O(|V|^3)
- 最坏时间:
O(|V|^3)
- 平均时间:
O(|V|^3)
- 最优时间:
Prim 算法
- **
Prim 算法
**是用于在带权无向图中计算最小生成树的贪婪算法。换言之,Prim 算法能够在图中抽取出连接所有节点的边的最小代价子集。 - 时间复杂度:
O(|V|^2)
Kruskal 算法
- **
Kruskal 算法
**同样是计算图的最小生成树的算法,与 Prim 的区别在于并不需要图是连通的。 - 时间复杂度:
O(|E|log|V|)
位运算
- 位运算即是在位级别进行操作的技术,合适的位运算能够帮助我们得到更快地运算速度与更小的内存使用。
- 测试第 k 位:
s & (1 << k)
- 设置第 k 位:
s |= (1 << k)
- 第 k 位置零:
s &= ~(1 << k)
- 切换第 k 位值:
s ^= ~(1 << k)
- 乘以 2n:
s << n
- 除以 2n:
s >> n
- 交集:
s & t
- 并集:
s | t
- 减法:
s & ~t
- 交换
x = x ^ y ^ (y = x)
- 取出最小非 0 位(Extract lowest set bit):
s & (-s)
- 取出最小 0 位(Extract lowest unset bit):
~s & (s + 1)
- 交换值:
x ^= y; y ^= x; x ^= y;
结语
未完待续......。
个人博客~
简书~
数据结构与算法(java)相关推荐
- 数据结构和算法(Java)-张晨光-专题视频课程
数据结构和算法(Java)-579人已学习 课程介绍 如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功. 想写出精炼.优秀的代码,不通过不断的锤炼,是很难做到的 ...
- 数据结构与算法-java笔记一 更新中
数据结构与算法-java笔记一 更新中 数据结构与算法 什么是数据结构.算法 数据结构学了有什么用: 线性结构 数组 特点 应用 链表 存储结构 链表类型 单链表 双向链表 双向循环链表 链表与数组的 ...
- 视频教程-内功修炼之数据结构与算法-Java
内功修炼之数据结构与算法 2018年以超过十倍的年业绩增长速度,从中高端IT技术在线教育行业中脱颖而出,成为在线教育领域一匹令人瞩目的黑马.咕泡学院以教学培养.职业规划为核心,旨在帮助学员提升技术技能 ...
- 02优先队列和索引优先队列-优先队列-数据结构和算法(Java)
文章目录 1 概述 1.1 需求 1.2 优先队列特点 1.3 优先队列分类 1.4 应用场景 1.5 相关延伸 2 说明 3 索引优先队列 3.1 实现思路 3.2 API设计 3.2 代码实现及简 ...
- 二叉查找树(1)-二叉树-数据结构和算法(Java)
文章目录 1 前言 1.1 二叉查找树定义 1.2 二叉查找树的性质 2 基本实现 2.1 API 2.2 实现代码 2.2.1 数据表示 2.2.2 查找 2.2.3 插入 3 分析 4 有序性相关 ...
- 数组【数据结构与算法Java】
数组[数据结构与算法Java] 数组 数组 略
- 0302Prim算法-最小生成树-图-数据结构和算法(Java)
文章目录 1 Prim算法 1.1 概述 1.1.1 算法描述 1.1.2 数据结构 1.1.3 横切边集合维护 1.2 延时实现 1.2.1 实现代码 1.2.2 性能分析 1.3 即时实现 1.3 ...
- 数据结构与算法Java(二)——字符串、矩阵压缩、递归、动态规划
不定期补充.修正.更新:欢迎大家讨论和指正 本文以数据结构(C语言版)第三版 李云清 杨庆红编著为主要参考资料,用Java来实现 数据结构与算法Java(一)--线性表 数据结构与算法Java(二)- ...
- java基础----数据结构与算法----Java API:集合 以及 排序相关API
概述: 基本数据结构与算法在jdk中都有相应的API 数组+java.util.Arrays java中的集合类 Collection-->List+Set-->接口的实现类 Map ...
- 数据结构和算法 java实现_数据结构与算法——常用数据结构及其Java实现
前言 仿佛一下子,2017年就快过去一半了,研一马上就要成为过去式了,我打算抓住研一的尾巴,好好梳理一下数据结构与算法,毕竟这些基础知识是很重要的嘛.所以准备在这里搞一个系列的文章,以期透彻. 本系列 ...
最新文章
- cv_bridge中的编码模式与实现
- 使用 jQuery Deferred 和 Promise 创建响应式应用程序
- 阿里云与WPS深度合作,开放数据处理生态
- SpringMVC的国际化
- 近期期刊制作组的工作计划
- 加密文件忘记密码怎么解密_MyBatis 配置文件 用户密码加密存储
- Flutter fvm 多版本管理
- 打造扛得住的MySQL数据库架构-第一课--影响数据库性能的因素
- win10休眠_电脑升级win10后,必做的5项优化,至少提升20%的运行速度
- 如何在树莓派中设置本地时区的问题解决
- 分享一款影视源码_爱客影院网站3.5.6版本
- 如何通过excel表格批量生成word文档?
- android字体右对齐,Android TextView将文本右对齐和左对齐
- Win10中文输入法加入美式英文键盘并默认英文键盘
- 云班课python测试答案_智慧职教云课堂APPPython程序设计题目答案
- 中国省市地图json数据包及解析
- 从牛顿定律到飞行器动力学
- SQL Server 数据库文件类型
- Learning Representations For Images With Hierarchical Labels(一、二)
- 知乎 mac apfs_APFS,Mac OS Extended(HFS +)和ExFAT之间有什么区别?