0 课程地址
https://coding.imooc.com/lesson/207.html#mid=13705
1 重点关注
1.1 结论
使用二叉树实现集合Set性能优于使用链表实现集合Set.
1.2 链表和二叉树实现 集合类复杂度分析
- 链表的时间复杂度为O(n),n为元素个数,
包含元素,contains方法时间复杂度为O(n),
增加元素,要首先用contains方法判断链表中是否有该元素,contains方法时间复杂度为O(n),
删除元素,while循环判断元素是否存在,存在则删除,所以复杂度也为O(n)
- 二叉树的时间复杂度为O(h),h为二叉树深度
包含元素,contains方法时间复杂度为O(h),每次基本上能过滤一半元素,时间复杂度为O(h),
增加元素,add方法递归调用,每次基本上能过滤一半元素,时间复杂度为O(h),
删除元素,每次基本上能过滤一半元素,时间复杂度为O(h),
- h和n的关系
满二叉树的情况,推导见1.3
n=2^h-1;
h = log2(n)
- 如果二叉树按照顺序排列,复杂度和链表复杂度一样,如何解决这种情况
使用平衡二叉树
1.3 h和n的关系推导
2 课程内容
3 Coding
3.1 链表和二叉树实现集合的性能测试
- 需求
分别使用链表和二叉树 实现的集合统计 傲慢与偏见 的英文词汇量,比较二者性能差异
- 结论:
二叉树性能要优于链表
- 链表类
package com.company;
/***
* 链表
* @author weidoudou
* @date 2022/10/28 7:56
**/
public class LinkedList<E> {
/**
* 1 内部类node
* @author weidoudou
* @date 2022/10/28 7:59
* @return null
**/
private class Node{
//Node 只有两个属性,下一个节点和本节点存储的元素
private E e;
private Node next;
/**
* 通用调用node方法
* @author weidoudou
* @date 2022/10/28 8:17
* @param e 请添加参数描述
* @param next 请添加参数描述
* @return null
**/
public Node(E e,Node next){
this.e = e;
this.next = next;
}
/**
* node 无参构造
* @author weidoudou
* @date 2022/10/28 8:15
* @return null
**/
public Node(){
this(null,null);
}
/**
* node 有参构造
* @author weidoudou
* @date 2022/10/28 8:16
* @param e 请添加参数描述
* @return null
**/
public Node(E e){
this(e,null);
}
@Override
public String toString() {
return e.toString();
}
}
//2 LinkedList 属性 链表头元素(火车头),大小
private int size;
private Node dummyHead;
/**
* 3 LikedList 无参
* @author weidoudou
* @date 2022/10/28 8:27
* @return null
**/
public LinkedList() {
this.dummyHead = new Node(null,null);
this.size = 0;
}
/**
* 4 getSize
* @author weidoudou
* @date 2022/10/28 8:23
* @return null
**/
public int getSize(){
return size;
}
/**
* 5 isEmpyt
* @author weidoudou
* @date 2022/10/28 8:24
* @return boolean
**/
public boolean isEmpty(){
return size == 0;
}
/**
* 6 链表头部添加元素
* @author weidoudou
* @date 2022/10/28 8:37
* @param e 请添加参数描述
* @return void
**/
public void addFirst(E e){
/*Node nodeNew = new Node(e);
nodeNew.next = head; //火车尾指向 上个尾巴
this.head = nodeNew; //火车尾 变成了当前的node*/
//称之为优雅写法
addElement(0,e);
}
/**
* 7 链表尾部添加元素 认真分析下
* @author weidoudou
* @date 2022/10/28 18:11
* @param e 请添加参数描述
* @return void
**/
public void addLast(E e){
addElement(size,e);
}
/**
* 8 链表添加元素(链表通常不在中间添加元素,编写此段代码完全是为了后续便于理解和二叉树相关知识做铺垫)
* @author weidoudou
* @date 2022/10/28 8:45
* @param index 请添加参数描述
* @param e 请添加参数描述
* @return void
**/
public void addElement(int index,E e){
if(index<0||index>size){
throw new IllegalArgumentException("索引不正确");
}
Node pre = dummyHead;
for(int i = 0;i<index;i++){
pre = pre.next;
}
/*Node nodeNew = new Node(e);
nodeNew.next = pre.next;
pre.next = nodeNew;*/
//优雅写法
pre.next = new Node(e,pre.next);
size++;
}
/**
* 9 查询
* @author weidoudou
* @date 2022/10/29 11:18
* @param index 请添加参数描述
* @return E
**/
public E findByIndex(int index){
if(index<0||index>size-1){
throw new IllegalArgumentException("索引越界");
}
Node cur = dummyHead.next;
for(int i = 0;i<index;i++){
cur = cur.next;
}
return cur.e;
}
/**
* A 查询首个元素
* @author weidoudou
* @date 2022/10/29 11:27
* @return E
**/
public E findByFirst(){
return findByIndex(0);
}
/**
* B 查询最后一个元素
* @author weidoudou
* @date 2022/10/29 11:27
* @return E
**/
public E findByLast(){
return findByIndex(size-1);
}
/**
* C 修改
* @author weidoudou
* @date 2022/10/29 11:29
* @param index 请添加参数描述
* @param e 请添加参数描述
* @return void
**/
public void update(int index,E e){
if(index<0||index>size-1){