裏裏裏裏裏个人主页 裏裏裏裏裏数据结构专栏 裏裏裏裏裏【数据结构】常见的排序算法

文章目录

1.前言2.搜索树2.1概念2.2查询操作2.3插入操作2.4删除操作2.5性能分析

1.前言

Map与Set的底层有两种结构实现,一种是搜索树(TreeMap与TreeSet),还有一个就是哈希表(HashMaP与HashSet),接下来我们先了解搜索树这个底层结构。

2.搜索树

2.1概念

二叉搜索树又称二叉排序树,它或者是一棵空树,搜索二叉树具备这样性质: 1)根结点的左边的结点都比根结点小 2)根结点的右边的结点都比根结点大 3)通过中序遍历来遍历这个二叉搜索树是一个升序的数据集合 搜索二叉树:

2.2查询操作

2.2.1 基本思路: 1.将要查询的值先于根结点比较,与根结点不相等,则判断该元素与根结点的大小。 2.根结点 > 该元素 则该元素在根结点的左边 3.根结点 < 该元素 则该元素在根结点的右边 4.遇到null则遍历结束

2.2.2绘图分析 2.2.3代码实现

/**

*寻找key元素

* @param key

* @return

*/

public boolean search(int key) {

TreeNode cur = root;

while(cur != null) {

//1.判断根结点

if(cur.val == key) {

return true;

} else if(cur.val > key) {

//2.根结点大于key

cur = cur.left;

} else {

//3.根结点小于key

cur = cur.right;

}

}

return false;

}

2.3插入操作

2.3.1基本思路: 1)插入的元素要满足中序遍历之后是一个升序的集合 2)插入的元素只能在搜索二叉树的叶子结点 进行插入 3) 通过一个指针来遍历要插入的位置的同时再让一个指针标记插入位置的父节点

遍历的过程: 1)root == null 直接插入 2)root != null 判断与根结点的大小关系 root.val > val 插入root左边 root.val < val 插入root右边 2.2.2绘图分析 2.2.3代码实现

/**

* 插入元素

*/

public void insert(int val) {

//1.root == null

if(root == null) {

root = new TreeNode(val);

return;

}

//2.root != null

TreeNode cur = root;

TreeNode parent = null;

while(cur != null) {

if(cur.val < val) {

//1.根结点小于key

parent = cur;

cur = cur.right;

} else {

//2.根结点大于key

parent = cur;

cur = cur.left;

}

}

//说明cur为空,元素插入parent结点的其中两侧

TreeNode node = new TreeNode(val);

if(parent.val < val) {

parent.right = node;

} else {

parent.left = node;

}

}

2.4删除操作

删除操作是最复杂也是最难的一个操作,我们以cur指针来标记删除结点,parent指针标记删除结点的父结点,我们对删除操作分为三种情况: 1.cur.left == null 2.cur.right == null 3.cur.left != null && cur.right != null 我们先画一棵搜索二叉树,这里我们删20这个结点为例子: 1.cur.left == null 2.cur.right == null 3.cur.left != null && cur.right != null 代码实现:

public boolean remove(int val) {

TreeNode cur = root;

TreeNode parent = null;

while(cur != null) {

if(cur.val < val) {

parent = cur;

cur = cur.right;

} else if(cur.val >val){

parent = cur;

cur = cur.left;

} else {

return removeNode(parent,cur);

}

}

return false;

}

private boolean removeNode(TreeNode parent,TreeNode cur) {

//1.cur.left == null

if(cur.left == null) {

if(cur == root) {

cur.right = root;

} else {

if(cur == parent.right) {

parent.right = cur.right;

}

if(cur == parent.left) {

parent.left = cur.right;

}

}

}

//2.cur.right == null

if(cur.right == null) {

if(cur == root) {

cur.left = root;

} else {

if(cur == parent.left) {

parent.left = cur.left;

}

if(cur == parent.right) {

parent.right = cur.left;

}

}

}

//3.cur.left !=null && cur.right != null

TreeNode child = cur.right;

TreeNode p = null;//p为child的父亲结点

while(child.left != null) {

p = child;

child = child.left;

}

//找到最小值,将最小值赋值给cur

cur.val = child.val;

//最小值的父亲结点的左节点是否等于最小值结点

if(p.left == child) {

p.left = child.right;

} else {

p.right = child.right;

}

return true;

}

2.5性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。 对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。 但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树: 最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:以2为底的log(N) 最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2

关于Map与Set先分享到这,后面的内容更加精彩,请各位看官慢慢期待。

文章链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。