2022-08-05 第二小组 张鑫 学习笔记
实训二十七天 集合
1.学习重点
1.树
2.集合结构
3.案例优化
2.学习心得
今天主要学习了数据结构中的树,还有集合的部分知识,晚上要做一个之前的项目,需要结合最近所学的很多知识,我要尝试挑战自己,争取把需求全部完成
3.学习内容
集合(最重要)
前提知识:数据结构——树
结点
结点是数据结构中的基础,构成复杂数据结构的基本组成单位
树(Tree)
是n(n>=0)个结点的有限集,n=0,称为空树
在任意的非空树中
1.有且只有一个特定的点称为根节点
2.当n>1时,其余节点可分为m个互不相交的有限集
定义树的时候
1.根结点是唯一的,不能存在多个根结点
2.子树的个数没有限制,但是一定互不相交
树的定义,使用了递归的方式
结点的度
结点拥有子结点的数量称为结点的度
结点关系
结点子树的根结点称为该结点的孩子结点
相应该结点称为孩子结点的父结点(双亲结点)
结点层次
树的深度
树中结点的最大层数称为树的深度或高度
二叉树
二叉树是n个结点的有限集合,如果n=0那就成为空二叉树
特点
1.每个结点最多有两个子结点,二叉树中不存在度大于2的结点
2.左子树和右子树是有顺序的,次序不能任意颠倒
3.即使树中某个结点只有一棵子树,也要区分是左子树还是右子树
性质
- 1.在二叉树中第i层上最多有2^(i-1)个结点(i>=1)
- 2.二叉树中深度为k,最多有2^k-1个结点(k>=1)
- 3.n0=n2+1,n0表示度数为0的结点,n2表示度数为2的结点
- 4.在完全二叉树中,具体n个结点的完全二叉树的深度为【log2n】+1,其中【log2n】向下取整
- 5.若对含n个结点的完全二叉树从上到下且从左到右进行1——n的标号,则对完全二叉树中任意一个编号为i的结点有如下特征
1.若i=1,则该节点为二叉树的根,无父节点,否则,编号为i/2的结点为其父节点
2.若2i>n,则该节点无左孩子结点,否则,编号为2i的结点为其左孩子结点
3.若2i+1>n,则该结点无右孩子结点,否则,编号为2i+1的结点为右孩子结点
斜树
所有的结点都只有左子树的二叉树叫做左斜树,所有的结点都只有右子树的二叉树叫做右斜树
满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有的叶子都在同一层上,这样的二叉树叫做满二叉树
满二叉树特点
1.叶子只能出现在下一层
2.非叶子结点的度一定是2
3.在同样深度的二叉树中,满二叉树的结点个数最多,叶子也最多
完全二叉树
对一棵具有n个结点的二叉树按层编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点位置相同
该二叉树称为完全二叉树
二叉树的存储结构
1.顺序存储
使用一维数组存储二叉树的结点,并且结点的存储位置就是数组的下标索引
当二叉树为完全二叉树时,结点数刚好填满数组
如果二叉树不是完全二叉树,采用顺序存储结构中已经出现了空间浪费的情况
例如右斜树极端情况,采用顺序存储十分浪费空间
顺序存储只适用于完全二叉树
2.二叉链表
顺序存储不能满足二叉树的存储需求,采用链式存储
二叉树的每个结点都有两个孩子
可以将结点数据结构定义成一个数据和两个指针域
数据结点
二叉树遍历
从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个节点被访问且仅被访问一次
二叉树的访问次序可以分为四种
递归遍历
自上而下,从左到右,每个结点会走三次
前序遍历:从二叉树的根结点出发,当第一次到达结点时就输出结点数据,按照先左后右的方向访问(根左右)
中序遍历:从二叉树的根结点出发,当第二次到达结点时就输出结点数据,按照先左后右的方向访问(左根右)
后序遍历:从二叉树的根结点出发,当第三次到达结点时就输出结点数据,按照先左后右的方向访问(左右根)
层次遍历:按照树的层次自上而下遍历二叉树;
class TreeNode<T>{
T data;//数据本身
TreeNode left;//左孩子
TreeNode right;//右孩子
public TreeNode(T data) {
this.data = data;
}
//前序遍历
//传入的参数就是根节点
public static void preorder(TreeNode root){
if (root == null) {
return;
}
System.out.println(root.data);
//递归
preorder(root.left);
preorder(root.right);
}
//中序
public static void inorder(TreeNode root){
if (root == null) {
return;
}
inorder(root.left);
System.out.println(root.data);
inorder(root.right);
}
//后序
public static void postorder(TreeNode root){
if (root == null) {
return;
}
postorder(root.left);
postorder(root.right);
System.out.println(root.data);
}
}
public class Ch01 {
public static void main(String[] args) {
TreeNode<Integer> root = new TreeNode<>(1);
root.left=new TreeNode(2);
root.right=new TreeNode(3);
root.left.left=new TreeNode(4);
root.left.right=new TreeNode(5);
root.right.left=new TreeNode(6);
root.right.right=new TreeNode(7);
TreeNode.preorder(root);
TreeNode.inorder(root);
TreeNode.postorder(root);
}
}
其他的树
1.二叉查找树
1.若左子树不为空,左子树所有的值小于它根结点的值
2.若右子树不为空,右子树所有的值大于它根结点的值
3.左右子树也是一个二叉查找树
4.没有键值相等的点
2.平衡二叉树(AVL树)
含有相同结点的二叉树的不同形态,找出一个查找平均长度最小的一棵二叉查找树
1.要么是一棵空树,要么其根结点的左右子树的深度差值不超过1
2.左右子树也都是平衡二叉树
3.二叉树结点的平衡因子定义为该结点的左子树的深度减去右子树的深度
平衡因子=左子树的深度-右子树的深度
3.红黑树
自平衡的二叉树,又增加了一个颜色的属性
结点的颜色只能是红色或黑色
1.根节点必须是黑色
2.红黑树中,所有的叶子结点后面再接上左右两个空结点,保持算法的一致性,所有空结点也都是黑色
3.其他结点要么是黑色,要么是红色,红色结点的父节点和左右孩子结点都是黑色,黑红相间
4.在任意一棵子树中,从根节点向下走到空结点的路径上所经历的黑结点数是相同的
4.B-树(B树)
B-树是一种平衡多路查找树,在文件系统中很有用,一棵m阶B-树
1.树中每个子节点至多有m棵子树
2.若根节点不是叶子节点,则至少有两棵子树
3.除根节点以外所有非终端节点至少有[m/2]棵子树
4.每个结点的信息结构(A0,K1,A1,K2..Kn,An)其中n表示关键字个数,K为关键字,A为指针
5.所有叶子节点都出现在同一层次上,且不带有任何信息
5.B+树
集合框架(重要)
集合
容器,存放数据的一个容器
使用集合的目的:更方便的存储和操作数据,CRUD
集合继承结构
Collection<E>:存放单值的最大父接口
List<E>(列表)线性表:和数组类似,List可以动态增长
查找元素效率高,插入删除元素的效率低,因为会引起其他元素位置改变
Set<E>线性表:检索元素效率低,插入和删除的效率高,插入和删除不会影响元素的移位
Map<K,V>:存放对值的最大父接口
Map(映射)用于保存具有映射关系的数据,Map保存着两组数据:key和value
key和value都可以是任意的引用数据类型,但是key不能重复
//创建了一个ArrayList集合
//开发中,一般情况下,使用多态创建集合
//向上转型
ArrayList<Integer> l1 = new ArrayList<>();
l1.add(1);
l1.add(2);
l1.add(3);
l1.add(4);
l1.add(5);
l1.add(1,-1);
List<Integer> l2 =new ArrayList<>();
l2.add(-1);
l2.add(-2);
l2.add(-3);
l2.add(-4);
l2.add(-5);
l2.add(1,100);
l1.addAll(l2);
l1.set(0,200);
l1.toArray();
//清空集合,集合中没有数据,集合为null
l1.clear();
l1.remove(Integer.valueOf(100));
System.out.println(l1);
System.out.println(l1.contains(-3));
System.out.println(l1.get(0));
System.out.println(l1.indexOf(1000));
System.out.println(l1.isEmpty());
//集合和数组之间的转换
//数组-->集合
int[]arr =new int[]{1,2,3,4,5};
List<int[]>arr1 =List.of(arr);
System.out.println(arr1.get(0)[0]);
List<Integer> integers = Arrays.asList(1,2,3,4,5);
List<Integer> integers1 = List.of(1,2,3,4,5);
1.如果初始化集合尽量指定初始化容量,如果确定不了,默认指定为16
2.使用泛型,数据的类型时候,一定要使用引用数据类型
public static void main(String[] args) {
List<Integer> l1 = new ArrayList<>(16);
l1.add(1);
l1.add(2);
l1.add(3);
l1.add(4);
l1.add(5);
l1.add(1,-1);
Integer [] arr = new Integer[]{1,2,3,4,5};
List<Integer> arr1 = List.of(arr);
List<Integer> integers = Arrays.asList(arr);
}
List集合中存放的数据
1.数据有顺序(添加的先后顺序)
2.数据可以重复
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本