《树(一)》

一 :为什么需要树这种数据结构

1) 数组存储方式分析

优点: 通过下标方式访问元素, 速度快。 对于有序数组, 还可以使用二分查找法并提高检索的速度。

缺点: 如果要检索某个具体的值, 或者插入值, 会造成整体移动, 效率较低

2) 链式存储方式分析

优点 : 在一定程度上对数组的存储方式有了优化(比如:插入,删除节点)

缺点 : 在进行检索时,仍然效率较低。

3 ) 树式存储方式分析

能提高数据的存储,读取速率,比如利用二叉排序树等。

二 : 二叉树的前, 中 , 后序遍历。

本质: 只是输出当前节点的顺序不同。

这是二叉树类

class BinaryTree {
    public Node root;

    public void setRoot(Node node) {
        root = node;
    }

    // 前序遍历
    public void preOrder() {
        if (root != null) {
            root.preOrder();
        }
    }

    // 中序遍历
    public void infixOrder() {
        if (root != null) {
            root.infixOrder();
        }
    }

    // 后序遍历
    public void postOrder() {
        if (root != null) {
            root.postOrder();
        }
    }
}

这是节点类。 

class Node {
    public int id;
    public String name;
    public Node left;
    public Node right;

    public Node(int id, String name) {
        this.id = id;
        this.name = name;
    }

    // 前序遍历
    public void preOrder() {
        System.out.println(this);
        if (this.left != null) {
            this.left.preOrder();
        }
        if (this.right != null) {
            this.right.preOrder();
        }
    }

    // 中序遍历
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }

        System.out.println(this);

        if (this.right != null) {
            this.right.infixOrder();
        }
    }

    // 后续遍历
    public void postOrder() {
        if (this.left != null) {
            this.left.postOrder();
        }
        if (this.right != null) {
            this.right.postOrder();
        }

        System.out.println(this);
    }


    @Override
    public String toString() {
        return "Node{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

三 : 前,中,后序查找

思路(以前序查找为例):

1) 先判断当前节点的值是否等于要查找的值, 如果相等, 则返回该节点

2) 如果不等, 判断当前节点的左子节点是否为空, 如果不为空, 则递归前序查找。

3) 如果左递归找到节点,则返回节点, 否则继续判断,当前节点的右字节点是否为空,如果不为空,则继续向右递归查找。

// 树
class BinaryTree {
    public Node root;


    // 前序遍历查找
    public Node preFind(int id) {
        if (root != null) {
            return root.preOrderFind(id);
        }
        return null;
    }
}
// 节点
class Node {
    public int id;
    public String name;
    public Node left;
    public Node right;

    public Node(int id, String name) {
        this.id = id;
        this.name = name;
    }

    

    // 前序遍历查找
    public Node preOrderFind(int id) {
        if (this.id == id) {
            return this;
        }

        Node findNode = null;
        if (this.left != null) {
            findNode = this.left.preOrderFind(id);
        }

        if (findNode != null) { // 说明已经找到,无需继续 right 查找
            return findNode;
        }

        if (this.right != null) {
            findNode = this.right.preOrderFind(id);
        }

        return findNode;
    }

四 : 二叉树删除节点

1) 如何删除的节点为叶子节点, 则删除该节点。

2) 如果删除的节点为非叶子节点, 则删除该子树(到二叉排序树时,在详分类)

步骤如下:


1) 考虑如果树是空树, 如果只有root 一个节点, 则等价将树置空。

2) 我们的二叉树是单向树, 所以我们判断的是 当前节点的子节点 是否需要删除节点, 而不能去判断当前节点是不是要删除的节点。

3) 如果当前节点的左子节点不为空, 并且左子节点就是要删除的节点, 就将 this . left = null, 并且返回。

4) 否则, 如果当前节点的右子节点不为空, 并且右子节点就是要删除的节点, 就将 this . right = null, 并且返回。

5 ) 如果 3, 4 步都没有删除节点, 则需要向左右子树进行递归删除

// 树
class BinaryTree {
    public Node root;

    public void setRoot(Node node) {
        root = node;
    }

    // 删除节点
    public void delete(int id) {
        if(root != null) {
            if(root.id == id) {
                root = null;
            } else {
                root.deleteNode(id);
            }
        }else {
            System.out.println("空树");
        }
    }
}
// 节点
class Node {
    public int id;
    public String name;
    public Node left;
    public Node right;

    public Node(int id, String name) {
        this.id = id;
        this.name = name;
    }


    public void deleteNode(int i) {
            // 判断左字节点是否是删除的节点
            if (this.left != null && this.left.id == id) {
                this.left = null;
                return;
            }
            // 判断右字节点
            if (this.right != null && this.right.id == id) {
                this.right = null;
                return;
            }

            // 如果都不是,则需要递归删除
            if (this.left != null) {
                this.left.deleteNode(id);
            }
            if (this.right != null) {
                this.right.deleteNode(id);
            }
    }
}

五:顺序存储二叉树

基本说明: 从数据的存储来看, 数组存储方式 和 树的存储方式可以相互转换, 即数组可以转换成树, 树也可以转换成数组。

特点: 

1) 顺序存储二叉树通常只会考虑完全二叉树

2) 第 n 个节点的左子节点为 2 * n + 1

3) 第 n 个节点的右子节点为 2 * n + 2

4) 第 n 个节点的父节点为 (n - 1)/ 2 (n 是数组的下标)

代码实现:

// 测试类
public class ArrBinaryTree {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7};
        ArrTree arrTree = new ArrTree();
        arrTree.setArr(arr);
        arrTree.preList();
    }
}
// 顺序存储二叉树
class ArrTree {
    public int[] arr;

    public void setArr(int[] arr) {
        this.arr = arr;
    }

    public void preList() {
        preList(0);
    }

    public void preList(int index) {
        if (arr == null || arr.length == 0) {
            System.out.println("空");
        }

        // 输出当前节点
        System.out.println(arr[index]);
        // 递归输出左子节点
        if ((2 * index + 1) < arr.length) {
            preList(2 * index + 1);
        }
        // 递归输出右字节点
        if((2 * index + 2) < arr.length) {
            preList(2 * index + 2);
        }
    }
}

六 : 堆排序

基本介绍:

1)堆排序是利用 堆 这种数据结构而设计的一种排序算法, 堆排序是一种选择排序, 它的最坏、最好、平均时间复杂度都为O(nlogn), 是不稳定的排序。

2)堆是具有以下性质的完全二叉树:每个节点的值大于或者等于其左右孩子的节点,称为大顶堆,每个节点的值小于或者等于其左右孩子节点的值,称为小顶堆。

3 )升序采用大顶堆, 降序采用小顶堆。

基本思想:

1) 将待排序列构造成一个大顶堆。

2) 此时,整个序列的最大值就是堆顶的根节点

3) 将其与末尾元素进行交换, 此时末尾就是最大值。

4) 然后将剩余 n - 1 个元素重新构造成一个堆, 这样会得到 n 个元素的次小值。 如此反复执行, 得到有序序列。

public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {4, 6, 8, 5, 9};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    // 编写堆排序方法
    public static void heapSort(int[] arr) {
        // arr.length / 2 - 1 这是第一个非叶子节点的节点下标
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            buildHeap(arr, i, arr.length);
        }

        for (int i = arr.length - 1; i > 0; i--) {
            swap(arr, 0, i);
            buildHeap(arr, 0 , i);
        }
    }

    // 将数组构建成一个大顶堆
    public static void buildHeap(int[] arr, int index, int size) {
        int temp = arr[index];
        for (int i = 2 * index + 1; i < size; i = i * 2 + 1) {
            if ((i + 1) < size && arr[i + 1] > arr[i]) {
                i = i + 1;
            }
            if (arr[i] > temp) {
                arr[index] = arr[i];
                index = i;
            } else {
                break;
            }
        }
        arr[index] = temp;
    }


    // 交换元素
    public static void swap(int[] arr, int l, int r) {
        int temp = arr[l];
        arr[l] = arr[r];
        arr[r] = temp;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值