做营销网站策划有什么前景,wordpress readd,公司请人做的网站打不开,与做网站有关的参考文献1.1 数据结构概述 Java的集合框架其实就是对数据结构的封装#xff0c;在学习集合框架之前#xff0c;有必要先了解下数据结构。 1.1.1 什么是数据结构 所谓数据结构#xff0c;其实就是计算机存储、组织数据的方式。 数据结构是用来分析研究数据存储操作的#xff0c;其实… 1.1 数据结构概述 Java的集合框架其实就是对数据结构的封装在学习集合框架之前有必要先了解下数据结构。 1.1.1 什么是数据结构 所谓数据结构其实就是计算机存储、组织数据的方式。 数据结构是用来分析研究数据存储操作的其实就是对数据做增删改查操作。 增把某个数据存储到某个容器中 删从容器中把某个数据删除掉 改把容器中某个数据替换成另一个数据 查把容器中的数据查询出来 开发意识 只要提到容器那核心操作一定是增删改查。 不同的数据结构底层采用不同的存储方式算法在具体操作的时候效率是不一样的比如有的查 询速度很快有的插入速度很快有的操作头和尾速度很快等。 1.1.2 为什么要熟悉数据结构 常见的数据结构 . 数组Array 链表Linked List 哈希表Hash 栈Stack 队列Queue 树Tree 图Graph 堆Heap 在未来具体业务场景时我们需要分析具体的需求场景是查询的操作多还是添加的操作多如果是 查询操作多我们就要选择适合查询性能高的集合如果添加操作多我们就需要选择添加性能高的集 合。 一句话根据具体业务场景选择合适的集合类。 1.2 数据结构 1.2.1 数组的性能分析 在计算机科学中算法的时间复杂度是一个函数它定性描述了该算法的运行时间常用大。符号来表 述。 时间复杂度是同一问题可用不同算法解决而一个算法的质量优劣将影响到算法乃至程序的效率。算法 分析的目的在于选择合适算法和改进算法。 我们在这里针对数组存储数据的增删改查CRUD做性能分析 添加操作 如果保存在数组的最后一个位置至少需要操作一次。 如果保存在数组的第一个位置如果存在N个元素此时需要操作N次(后面的元素要整体后移)。 平均: (N1) /2 次。 N表示数组中元素的个数。 如果要扩容更慢性能更低。 删除操作: 如果删除最后一个元素操作一次。 如果删除第一个元素操作N次。 平均(N1) / 2次. 修改操作: 给定索引时操作1次. 查询操作根据索引查询元素需要操作1次根据内容查询需要N次 结论基于数组的数据结构做查询是和修改是非常快的添加和删除操作比较慢了。 那如果想保证保存和删除操作的性能此时就得提提链表这种数据结构了。 1.2.2 其他线性数据结构 1.2.1. 链表了解 链表结构火车和火车车厢 1)单向链表只能从头遍历到尾/只能从尾遍历到头。 2)双向链表既可以从头遍历到尾,又可以从尾遍历到头。 通过引用来表示上一个节点和下一个节点的关系。 单向链表 双向链表 对链表操作的性能分析 双向链表可以直接获取自己的第一个和最后一个节点。 添加操作 如果新增的元素在第一个或最后一个位置那么操作只有1次。 删除操作 如果删除第一个元素 操作一次 如果删除最后一个元素操作一次 如果删除中间的元素 ① 找到元素节点平均操作 (1N ) / 2次 ② 找到节点之后做删除操作: 1次 修改操作 平均(N1)/2次 查询操作: 平均:(N1)/2次 结论 数组 查询、更改较快新增和删除较慢。 链表 查询、更改较慢新增和删除较快。 1.2.2. 队列 队列是一种特殊的线性表特殊之处在于它只允许在表的前端front进行删除操作而在表的后端 rear进行插入操作队列是一种操作受限制的线性表。 进行添加操作的端称为队尾进行删除操作的端称为队头。 单向队列(Queue)先进先出(FIFO)只能从队列尾插入数据只能从队列头删除数据。 双向队列(Deque)可以从队列尾/头插入数据只能从队列头/尾删除数据。 结论最擅长操作头和尾。 1.2.3. 栈了解 栈stack又名堆栈它是一种运算受限的线性表后进先出(LIFO)和手枪弹夹类似。 栈结构仅允许在表的一端进行插入和删除运算这一端被称为栈顶相对地把另一端称为栈底。 向一个栈中插入新元素又称作入栈它是把新元素放到栈顶元素的上面使之成为新的栈顶元素。从一 个栈中删除元素又称作出栈表示把栈顶元素删除掉使其相邻的元素成为新的栈顶元素LIFO。 1.3 非线性数据结构 1.3.1. 哈希表 一般的数组中元素在数组中的索引位置是随机的元素的取值和元素的位置之间不存在确定的对 应关系。因此在数组中查找特定的值时需要把查找值和一系列的元素进行比较。 此时的查询效率依赖于查找过程中所进行的比较次数如果比较次数较多查询效率还是不高。 如果元素的值value和在数组中的索引位置index有一个确定的对应关系我们把这种关系 称之为哈希hash。则元素值和索引对应的公式为: index hash(value)。也就是说通过给定元素 值只要调用hash(value)方法就能找到数组中取值为value的元素的位置。 比如图中的hash算法公式为 index value / 10 - 1。 在往哈希表中存储对象时该hash算法就是对象的hashCode方法。 注这里仅仅是假设算法公式是这样的真实的算法公式我们可以不关心。 1.3.4. 树和二叉树 前面我们介绍的数据结构数组、栈、队列链表都是线性数据结构除此之外还有一种比较复杂的 数据结构——树。 计算机中的树是根据生活中的树抽象而来的表示N个有父子关系的节点的集合。 N为0的时候该节点集合为空这棵树就是空树 任何非空树中有且只有一个根节点root N1时一颗树由根和若干棵子树组成每棵子树由更小的若干子树组成 树中的节点根据有没有子节点分成两种 普通节点拥有子节点的节点。 叶子节点没有字节点的节点。 二叉树一种特殊的遵循某种规则的树。 树的结构因为存在多种子节点情况真的太复杂了如果我们对普通的树加上一些约束比如让每 一棵树的节点最多只能包含两个子节点而且严格区分左子节点和右子节点左右位置不能交换此 时就形成了二叉树。 排序二叉树有顺序的树 若左子树不为空则左子树所有节点的值小于根节点的值。 若右子树不为空则右子树所有节点的值大于根节点的值。 左右子树也分别是排序二叉树。 红黑树更高查询效率的的排序二叉树。 排序二叉树可以快速查找但是如果只有左节点或者左右右节点的时候此时二叉树就变成了普通 的链表结构查询效率比较低。为此一种更高效的二叉树出现了——红黑树。 每个节点要么是红色的要么是黑色的。 根节点永远是黑色的。 . 所有叶子节点都是空节点null是黑色的。 每个红色节点的两个子节点都是黑色的。 从任何一个节点到其子树每个叶子节点的路径都包含相同数量的黑色节点。 1.3 集合框架体系 1.3.1 集合框架概述 集合是Java中提供的一种容器可以用来存储多个数据根据不同存储方式形成的体系结构就叫做集 合框架体系。集合也时常被称为容器。 每一种容器类底层拥有不同的底层算法(数据结构)。 既然数组可以存储多个数据为什么要出现集合 数组的长度是固定的集合的长度是可变的。 使用Java类封装出一个个容器类开发者只需要直接调用即可不用再手动创建容器类。 集合中存储的数据叫做元素(element)元素只能是对象引用类型。 在Java中集合操作都被设计成接口被不同底层数据结构的实现类所实现。 1.3.2 集合的分类 根据容器的存储特点的不同可以分成三种情况 . List(列表)允许记录元素的添加顺序允许元素重复。 . Set(数据集)不记录元素的添加顺序不允许元素重复。 . Map(映射)容器中每一个元素都包含一对key和value key不允许重复 value可以重复。严格上 说并不是容器集合是两个容器中元素映射关系。 注意 List和Set接口继承于Collection接口 Map接口不继承Collection接口。 Collection接口泛指广义上集合主要表示List和Set两种存储方式。 List接口表示列表规定了允许记录添加顺序允许元素重复的规范。 Set接口表示狭义上集合规定了不记录添加顺序不允许元素重复的规范。 Map接口表示映射关系规定了两个集合映射关系的规范。 注意我们使用的容器接口或类都处于java.util包中。 1.4 List接口 List接口是Collection接口子接口 List接口定义了一种规范要求该容器允许记录元素的添加顺 序也允许元素重复。那么List接口的实现类都会遵循这一种规范。 List集合存储特点 允许元素重复 允许记录元素的添加先后顺序 该接口常用的实现类有 ArrayList类数组列表表示数组结构底层采用数组实现开发中使用最多的实现类重点。 LinkedList类链表表示双向列表和双向队列结构采用链表实现使用不多。 Stack类栈表示栈结构采用数组实现使用不多。 Vector类向量其实就是古老的ArrayList采用数组实现使用不多。 一般来说集合接口的实现类命名规则底层数据结构 接口名例如 ArrayList 1.4.1. List常用API方法 添加操作 . boolean add(object e)将元素添加到列表的末尾 . void add(int index, object element)在列表的指定位置插入指定的元素 . boolean addAll(Collection c)把c列表中的所有元素添加到当前列表中 删除操作 . object remove(int index)从列表中删除指定索引位置的元素,并返回被删除的元素 . boolean removeAll(Collection c)从此列表中移除c列表中的所有元素 修改操作 . object set(int index, object ele)修改列表中指定索引位置的元素返回被替换的旧元素 查询操作 . int size()返回当前列表中元素个数 . boolean isEmpty()判断当前列表中元素个数是否为0 . object get(int index)查询列表中指定索引位置对应的元素 object[] toArray()把列表对象转换为object数组 . boolean contains(object o):判断列表是否存在指定对象 注意标红的是经常使用的方法。 1.4.2.ArrayList类 ArrayList类基于数组算法的列表通过查看源代码会发现底层其实就是一个object数组。 需求1操作List接口常用方法 public class ArrayListDemo { public static void main(String[] args) { // 创建一个默认长度的列表对象 List list new ArrayList(); // 打印集合中元素的个数 System.out.println(元素数量list.size());//0 // 添加操作向列表中添加4个元素 list.add(Will); list.add(100); list.add(true); list.add(Lucy); // 查询操作: System.out.println(列表中所有元素list);//输出 :[Will, 100, true, Lucy] System.out.println(元素数量list.size());//4 System.out.println(第一个元素list.get(0));//Will // 修改操作把索引为2的元素替换为wolfcode list.set(2, wolfcode); System.out.println(修改后list);//输出 :[Will, 100, wolfcode, Lucy] // 删除操作删除索引为1的元素 list.remove(1); System.out.println(删除后list);//输出 :[Will, wolfcode, Lucy] } } 需求2创建四个User对象存储在List中分析内存图。 public class User { private String name; private int age; //省略两个参数构造器 // getter/setter方法 // 需要重写toString方法 } public class ArrayListDemo2 { public static void main(String[] args) { List girls new ArrayList(); User u1 new User(西施, 18); girls.add(u1); girls.add(new User(王昭君,19)); girls.add(new User(貂蝉,20)); girls.add(new User(杨玉环,21)); System.out.println(girls); //修改u1对象的名字和年龄 u1.setName(小施); u1.setAge(17); System.out.println(girls); } } 运行结果观察变化 [User [name西施 , age18], User [name王昭君 , age19], User [name貂蝉 , age20], User [name杨玉环 , age21]] [User [name小施 , age17], User [name王昭君 , age19], User [name貂蝉 , age20], User [name杨玉环 , age21]] 内存分析解释原因 结论集合类中存储的对象,都存储的是对象的引用,而不是对象本身。 1.4.3.LinkedList类 ArrayList类基于数组算法的列表通过查看源代码会发现底层其实就是一个object数组。 LinkedList类底层采用链表算法实现了链表队列栈的数据结构。无论是链表还是队列主要 操作的都是头和尾的元素因此在LinkedList类中除了List接口的方法还有很多操作头尾的方法。 . void addFirst(object e) 将指定元素插入此列表的开头。 . void addLast(object e) 将指定元素添加到此列表的结尾。 object getFirst() 返回此列表的第一个元素。 object getLast() 返回此列表的最后一个元素。 object removeFirst() 移除并返回此列表的第一个元素。 object removeLast() 移除并返回此列表的最后一个元素。 总结以上API都是返回异常的。 . boolean offerFirst(object e) 在此列表的开头插入指定的元素。 . boolean offerLast(object e) 在此列表末尾插入指定的元素。 . object peekFirst() 获取但不移除此列表的第一个元素如果此列表为空则返回 null。 . object peekLast() 获取但不移除此列表的最后一个元素如果此列表为空则返回 null。 . object pollFirst() 获取并移除此列表的第一个元素如果此列表为空则返回 null。 . object pollLast() 获取并移除此列表的最后一个元素如果此列表为空则返回 null。 . void push(object e) 将元素推入此列表所表示的栈。 . object pop() 从此列表所表示的栈处弹出一个元素。 . object peek() 获取但不移除此列表的头第一个元素。 LinkedList之所以有这么多方法是因为自身实现了多种数据结构而不同的数据结构的操作方法 名称不同在开发中LinkedList使用不是很多知道存储特点就可以了。 public class LinkedListDemo { public static void main(String[] args) { LinkedList list new LinkedList(); //添加元素 list.addFirst(A); list.addFirst(B); System.out.println(list); list.addFirst(C); System.out.println(list); list.addLast(D); System.out.println(list); //获取元素 System.out.println(获取第一个元素 list.getFirst());//C System.out.println(获取最后一个元素 list.getLast());//D //删除元素 list.removeFirst(); System.out.println(删除第一个元素后 list);//[B, A, D] list.removeLast(); System.out.println(删除最后一个元素后 list);//[B, A] } } 程序运行结果 [B, A] [C, B, A] [C, B, A, D] 获取第一个元素C 获取最后一个元素D 删除第一个元素后 [B, A, D] 删除最后一个元素后 [B, A] 1.4.4. Stack和Vector类 Vector类基于数组算法实现的列表其实就是ArrayList类的前身。和ArrayList的区别在于方法使用 synchronized修饰所以相对于ArrayList来说线程安全但是效率就低了点。 Stack类表示栈是Vector类的子类具有后进先出(LIFO)的特点拥有push入栈 pop出栈 方法。 1.5. 泛型 1.5.1. 什么是泛型 其实就是一种类型参数 主要用于某个类或接口中数据类型不确定时可以使用一个标识符来表示 未知的数据类型 然后在使用该类或接口时指定该未知类型的真实类型。 泛型可用到的接口、类、方法中将数据类型作为参数传递其实更像是一个数据类型模板。 如果不使用泛型从容器中获取出元素需要做类型强转也不能限制容器只能存储相同类型的元 素。 List list new ArrayList(); list.add(A); list.add(B); String ele (String) list.get(0); 1.5.2. 自定义和使用泛型 定义泛型使用一个标识符比如T在类中表示一种未知的数据类型。 使用泛型 一般在创建对象时给未知的类型设置一个具体的类型当没有指定泛型时默认类型 为Object类型。 需求定义一个类Point x和y表示横纵坐标分别使用String、 Integer、 Double表示坐标类型。 如果没有泛型需要设计三个类如下 定义泛型 //在类上声明使用符号T,表示未知的类型 //在类上声明使用符号T,表示未知的类型 public class PointT { private T x; private T y; //省略getter/setter } 使用泛型 // 没有使用泛型未指明泛型默认类型是object Point p1 new Point(); object x1 p1.getX(); //使用String作为泛型类型指明泛型为String类型 PointString p2 new PointString(); String x2 p2.getX(); //使用Integer作为泛型类型指明泛型为Double类型 PointInteger p3 new PointInteger(); Integer x3 p3.getX(); 画图分析 注意这里仅仅是演示泛型类是怎么回事并不是要求定义类都要使用泛型。 1.5.3. 在集合框架中使用泛型 拿List接口和ArrayList类举例。 class ArrayListE{ public boolean add(E e){ } public E get(int index){ } } 此时的E也仅仅是一个占位符表示元素Element的类型那么当使用容器时给出泛型就表示该 容器只能存储某种类型的数据。 //只能存储String类型的集合 ListString list1 new ArrayListString(); list1.add(A); list1.add(B); //只能存储Integer类型的集合 ListInteger list2 new ArrayListInteger(); list2.add(11); list2.add(22);
因为前后两个泛型类型相同也必须相同泛型类型推断 ListString list1 new ArrayListString(); 可以简写为 ListString list1 new ArrayList();
通过反编译工具会发现泛型其实是语法糖也就是说编译之后泛型就不存在了。
注意泛型必须是引用类型不能是基本数据类型错误如下 Listint list new ArrayListint();//编译错误
泛型不存在继承的关系错误如下 Listobject list new ArrayListString(); //错误的