综述
数据结构包括: 数组、链表、栈、二叉树、哈希表 等等,算法对这些结构中的数据进行各种处理
- 现实世界数据存储
- 程序员的工具
- 建模
数据结构特点概述
数据库 | 优点 | 缺点 |
---|---|---|
数组 | 插入快,如果知道下标,可以非常快的存取 | 查找慢,删除慢,大小固定 |
有序数组 | 比无序的数组查找快 | 删除和插入慢,大小固定 |
栈 | 提供 后进先出 方式的存取 | 存取其他项很慢 |
队列 | 提供 先进先出 方式的存取 | 存取其他项很慢 |
链表 | 插入快 删除快 | 查找慢 |
二叉树 | 查找、插入、删除都快(如果树保持平衡) | 删除算法 复杂 |
红-黑树 | 查找 插入 删除都快 树总是平衡的 | 算法复杂 |
2-3-4 树 | 查找 插入 删除 都很快 树总是平衡的, 类似的 树 对磁盘存储有用 | 算法复杂 |
哈希表 | 如果关键字已知 则存取极快,插入快 | 删除慢,如果不知道关键字存取 很慢, 对存储空间使用不充分 |
堆 | 插入 删除快 对最大数据项的存取很快 | 对其他数据项存取慢 |
图 | 对 现实世界 建模 | 有些算法慢且 复杂 |
抽象数据结构 (ADT)
对于大多数据结构来说,需要知晓:
- 插入一条新的数据项
- 寻找某一特定的数据项
- 删除某一特定的数据项
插入 寻找 删除
还需要知道 如何迭代的访问,某一数据结构的个数据项,以便 显示 或其他操作
小结
- 数据结构是指数据在计算机内存空间中或磁盘中的组织形式
- 正确的选择数据结构会使程序的效率大大提高
- 数据结构的例子由数组,栈和链表
- 算法是完成特定任务的过程
- 在JAVA中,算法经常通过类的方法实现
递归
- 本质上,将原来的问题,转化为更小的同一问题
设计转换逻辑的时候,注意递归函数的"宏观"语意
递归函数就是一个函数,完成一个功能
// 计算 arr[l...n) 范围里的数字和
public static int sum(int[] arr, int l){
if(l == arr.length)
return 0; // 求解最基本问题
return arr[l] + sum(arr,l+1); // 把原问题转化为更小的问题
}
Java 数据结构 | 菜鸟教程
Java 数据结构
Java 数据结构主要包括以下几种接口和类:
- 枚举
- 位集合
- 向量
- 栈
- 字典 : 它定义了键映射到值的数据结构
- 哈希表
- 属性 (Properties)
Java集合框架
集合框架是一个用来代表和操纵集合的统一架构,所有的集合框架都包含如下内容:
- 接口: 是代表集合的抽象数据类型
- 实现(类): 是集合接口的具体实现
- 算法: 是实现集合接口的对象里的方法执行的一些有用的计算
Set 和 List 的区别
- Set 接口实例存储的是无序的,不重复的数据。 List 接口实例存储的是有序的,可以重复的元素
- Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>
- List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List 长度,查找元素效率高,插入删除效率低,因为会引起其他元素位置改变<实现类有ArrayList,LinkedList,Vector>
public class runoobInterface {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("Haaa");
// 第一种遍历方法使用 For-each 遍历 List
for (String str : list){
System.out.println(str);
}
// 迭代器遍历
Iterator<String> ite = list.iterator();
while (ite.hasNext()){
System.out.println(ite.next());
}
// 遍历 Map
Map<String, String> map = new HashMap<String, String>();
map.put("1","value1");
map.put("2","value2");
map.put("3","value3");
// 通过Map.entrySet遍历key 和 value
for (Map.Entry<String,String> entry : map.entrySet()){
entry.getKey(); // 获取key
entry.getValue(); // 获取Value
}
}
}
Java ArrayList
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素
ArrayList 继承AbstractList 实现List 接口
package com.weirui.lesson4;
import java.util.ArrayList;
// ArrayList 是一个数组队列
public class runoobArrayList {
public static void main(String[] args) {
// 添加元素
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("Google");
arrayList.add("Runoob");
arrayList.add("BaiDu");
arrayList.add("WeiBo");
System.out.println(arrayList);
// 访问元素 使用get()方法
System.out.println(arrayList.get(0));
//访问对应下标 数组索引值从0开始
// 修改元素 使用set() 方法
arrayList.set(1,"WiKi");
System.out.println(arrayList);
//删除元素 使用remove() 方法
arrayList.remove(3);
System.out.println(arrayList);
// 计算大小 使用size() 方法
System.out.println("大小为: " + arrayList.size());
// 迭代数组列表 使用for-each 来迭代元素
for (String i : arrayList){
System.out.println(i);
}
// ArrayList 排序 使用 sort()方法可以对字符或数字列表进行排序
}
}
Java LinkedList
链表是一种常见的基础数据结构,是一种线性表,但是不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址
public class runoobLinkedList {
public static void main(String[] args) {
// 引入LinkedList 类
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("Google");
linkedList.add("Runoob");
linkedList.add("Taobao");
linkedList.add("Weibo");
System.out.println(linkedList);
// 使用 addFirst() 在头部添加元素
linkedList.addFirst("Wiki");
// 使用 addLast() 在尾部添加元素
linkedList.addLast("Wiki");
// 使用 removeFirst() 移除头部元素
linkedList.removeFirst();
// 使用 removeLast() 移除尾部元素
linkedList.removeLast();
// 使用 getFirst() 获取头部元素
// 使用 getLast() 获取尾部元素
}
}
Java HashSet
是一个不允许有重复元素的集合,允许有null值
Java HashMap
HashMap 是一个散列表,它存储的内容是键值对(Key - Value)映射
Map<String, String> map = Map.of("google","google.com","Runoob","Runoob.com");
Map<Integer, String> map = Map.of("1","google.com","2","Runoob.com");
// 创建一个HashMap 对象 Sites
HashMap<Integer,String> Sites = new HashMap<Integer,String>();
// 添加元素
Sites.put(1, "Google");
// 访问元素 使用 get(key) 方法来获取 key 对应的 values
Sites.get(1);
// 删除元素 使用 remove(key) 方法来删除 key 对应的键值对(key-value)
Sites.remove(1);
// 删除所有键值对 使用clear 方法
Sites.clear();
// 计算大小 使用size() 方法
// 获取 key,可以使用 keySet()
// 通过 get(key) 获取对应的 value
// 只想获取 value,可以使用 values()
Java Iterator (迭代器)
Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法
迭代器 it 的两个基本操作是 next,hasNext 和 remove
调用 it.next() 会返回迭代器的下一个元素,并且更新迭代器的状态。
调用 it.hasNext() 用于检测集合中是否还有元素。
调用 it.remove() 将迭代器返回的元素删除。
Java Object
Java Object 类是所有类的父类,Java所有的类都继承了Object 子类可以使用Object 的所有方法
Java Object clone()
创建并返回一个对象的拷贝,clone方法是浅拷贝,对象内属性引用的对象只会拷贝引用地址,而不会将引用对象重新分配内存
Java 泛型
泛型是JDK5 引入的新特性,泛型提供了编译时类型安全检测机制,泛型本质是参数化类型
Java 序列化
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
Labuladong
数据结构种类很多,但它们存在的目的都是在不同的应用场景,尽可能高效地增删查改
线性就是 for/while 迭代为代表,非线性就是递归为代表
数组遍历框架,典型的线性迭代结构:
void traverse(int[] arr){
for(int i = 0;i < arr.length; i++){
//迭代访问 arr[i];
}
}
链表遍历框架,兼具迭代和递归结构:
/* 基本的单链表节点*/
class ListNode{
int val;
ListNode next;
}
void traverse(ListNode head){
for(ListNode p = head; p!= null; p = p.next){
// 迭代访问 p.val
}
}
void traverse(ListNode head){
// 递归访问head.val
traverse(head.next);
}
二叉树遍历框架,典型的非线性递归遍历结构
// 基本的二叉树节点
class TreeNode{
int val;
TreeNode left,right;
}
void traverse(TreeNode root){
traverse(root.left);
traverse(root.right);
}
二叉树和链表的递归遍历如此类似
那么对应:二叉树框架可以扩展为N叉树的遍历框架
// 基本的 N 叉树节点
class TreeNode{
int val;
TreeNode[] children;
}
void traverse(TreeNode root){
for(TreeNode child : root.children){
traverse(child);
}
}
二叉树思路框架
void traverse(TreeNode root){
// 前序遍历
traverse(root.left);
// 中序遍历
traverse(root.right);
// 后序遍历
}
只要涉及递归的问题,都是树的问题,很多动态规划就是在遍历一棵树
刷算法题尝试从[树]分类开始刷