算法第二部分(2)

算法第六章

树结构

非线性

树结构本身是一种天然的组织结构 (文件目录结构,企业层级结构)

将数据使用树结构存储后,出奇的高效

二分搜索树

二叉树:和链表一样,是动态的数据结构
在这里插入图片描述
二叉树具有唯一跟节点(左孩子和右孩子)

二叉树具有天然递归结构(链表是线性的,循环更好处理)

二叉树不一定是满的

二分搜索树是二叉树

二分搜索树的每个节点的值:

​ 大于其左子树的所有节点的值

​ 小于其右子树的所有节点的值

存储的元素必须具有可比较性

我们的二分搜索树不包含重复元素

​ 如果想包含重复元素的话,只需要定义:

​ 左子树小于等于节点,或者右子树大于等于节点

二分搜素树的遍历

所有节点都访问一遍。

后序遍历的一个应用(为二分搜索树释放内存)

深度优先遍历(前序,中序,后序)

层序遍历(通常使用非递归)

二分搜索树具有顺序性 ,同时可以拿到前驱和后继。拿到一个数的floor和tail

二分搜索树代码实现:
public class BST<E extends Comparable<E>> {
    private class Node{
        public E e;
        public Node left,right;

        public Node(E e){
            this.e=e;
            left=null;
            right=null;
        }
    }
    private Node root;
    private int size;

    public BST(){
        root=null;
        size=0;
    }
    public int getSize(){
        return size;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public void add(E e){
        root=add(root,e);
    }
    //向以node为跟的二分搜索树种插入元素E,递归算法
    private Node add(Node node,E e){
        /*if(e.equals(node.e)){
            return;
        }else if(e.compareTo(node.e)<0&& node.left==null){
            node.left=new Node(e);
            size++;
            return;
        }else if(e.compareTo(node.e)>0&&node.right==null){
            node.right=new Node(e);
            size++;
            return;
        }*/
        if(node==null){
            size++;
            return new Node(e);
        }
        if(e.compareTo(node.e)<0){
            node.left=add(node.left,e);
        }else if(e.compareTo(node.e)>0){
            node.right=add(node.right,e);
        }
        return node;
    }
    //看二分搜索树种是否包含元素e
    public boolean contains(E e){
        return contains(root,e);
    }

    private boolean contains(Node node,E e){
        if(node==null){
            return false;
        }
        if(e.compareTo(node.e)==0){
            return true;
        }else if(e.compareTo(node.e)<0){
            return contains(node.left,e);
        }else{
            return contains(node.right,e);
        }
    }
    //二分搜索树的前序遍历
    public void preOrder(){
       preOrder(this.root);
    }

    private void preOrder(Node node){
        if(node==null){
            return;
        }
        System.out.println(node.e);
        preOrder(node.left);
        preOrder(node.right);
    }

    public void inOrder(){
        inOrder(this.root);
    }

    private void preOrderNR(){
        Stack<Node> stack=new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            Node cur=stack.pop();
            System.out.println(cur.e);

            if(cur.right!=null){
                stack.push(cur.right);
            }
            if(cur.left!=null){
                stack.push(cur.left);
            }
        }

    }

    private void inOrder(Node node){
        if(node==null){
            return;
        }
        inOrder(node.left);
        System.out.println(node.e);
        inOrder(node.right);
    }

    public static void main(String[] args) {
        //      5
        //   3      6
        // 2  4       8
        BST<Integer> bst=new BST<>();
        int[] nums={5,3,6,8,4,2};
        for (int num:
             nums) {
            bst.add(num);
        }
        bst.remove(3);
        //bst.preOrder();
        //System.out.println(bst.toString());
        //bst.inOrder();
        //bst.preOrderNR();
        bst.levelOrder();
      /*  Random random=new Random();
        int n=1000;
        for (int i=0;i<n;i++){
            bst.add(random.nextInt(10000));
        }
        ArrayList<Integer> nums=new ArrayList<>();
        while (!bst.isEmpty()){
            nums.add(bst.removeMin());
        }
        System.out.println(nums);
        for (int i=1;i<nums.size();i++){
            if(nums.get(i-1)>nums.get(i)){
                throw new IllegalArgumentException("ERROR");
            }
        }
        System.out.println("test completed");*/
    }

    //二分搜索树的层序遍历
    public void levelOrder(){
        Queue<Node> queue=new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            Node cur= queue.remove();
            System.out.println(cur.e);
            if(cur.left!=null){
                queue.add(cur.left);
            }
            if(cur.right!=null){
                queue.add(cur.right);
            }
        }

    }

    //寻找二分搜索树的最小元素
    public E minimum(){
        if(size==0){
            throw new IllegalArgumentException("BST is empty");
        }
       return minimum(root).e;
    }
    //返回以node为根的二分搜索树的最小值所在的节点
    private Node minimum(Node node) {
        if(node.left==null){
            return node;
        }
        return minimum(node.left);
    }

    //寻找二分搜索树的最小元素
    public E maximum(){
        if(size==0){
            throw new IllegalArgumentException("BST is empty");
        }
        return minimum(root).e;
    }
    //返回以node为根的二分搜索树的最小值所在的节点
    private Node maximum(Node node) {
        if(node.right==null){
            return node;
        }
        return maximum(node.right);
    }
    public E removeMin(){
        E ret=minimum();
        root=removeMin(root);
        return ret;
    }
    //删除掉以node为根的二分搜索树中最小节点
    //返回删除节点后新的二分搜索树的根
    private Node removeMin(Node node){
        //删掉当前节点
        if(node.left==null){
            //如果node.right也等于null
            Node rightNode=node.right;
            node.right=null;
            size--;
            return rightNode;
        }
        node.left=removeMin(node.left);
        return node;
    }

    public E removeMax(){
        E ret=minimum();
        root=removeMax(root);
        return ret;
    }
    //删除掉以node为根的二分搜索树中最大节点
    //返回删除节点后新的二分搜索树的根
    private Node removeMax(Node node){
        //删掉当前节点
        if(node.right==null){
            Node rightNode=node.left;
            node.left=null;
            size--;
            return rightNode;
        }
        node.right=removeMax(node.right);
        return node;
    }

    //从二分搜索树中删除元素为e的节点
    public void remove(E e){
        root=remove(root,e);
    }
    //删除掉以node为根的二分搜索树中值为e的节点,递归算法
    //返回删除节点后新的二分搜索树的根
    private Node remove(Node node, E e) {
        if(node==null){
            return null;
        }
        //e<node.e 要删除的数小于当前数
        if(e.compareTo(node.e)<0){
            node.left=remove(node.left,e);
            return node;
        }else if(e.compareTo(node.e)>0){
            node.right=remove(node.right,e);
            return node;
        }else{
            //查找到需要删除的数
            //待删除节点左子树为空的情况,应该直接把删除节点右子树转接到该节点的位置
            if(node.left==null){
                Node rightNode=node.right;
                node.right=null;
                size--;
                return rightNode;
            }
            //待删除节点右子树为空的情况
            if(node.right==null){
                Node leftNode=node.left;
                node.left=null;
                size--;
                return leftNode;
            }

            //待删除节点左右子树均不为空的情况
            //找到比待删除节点大的最小节点,即待删除节点右子树的最小节点
            //用这个节点顶替待删除节点的位置
            Node successor=minimum(node.right);
            successor.right=removeMin(node.right);
            successor.left=node.left;
            node.left=node.right=null;
            return successor;
        }

    }

    @Override
    public String toString(){
        StringBuilder res=new StringBuilder();
        generateBSTString(root,0,res);
        return res.toString();
    }

    /**
     * 自下而上创建,--递增(depth)
     * @param node
     * @param depth
     * @param res
     */
    private void generateBSTString(Node node, int depth, StringBuilder res) {
        if(node==null){
           res.append(generateDepthString(depth)+"null\n");
           return;
        }
        //访问节点在访问其子节点之前,称为前序遍历   前中后 中序遍历   前后中 后序遍历

        generateBSTString(node.left,depth+1,res);
        res.append(generateDepthString(depth)+node.e+"\n");
        generateBSTString(node.right,depth+1,res);

    }
    private String generateDepthString(int depth) {
        StringBuilder res=new StringBuilder();
        for (int i=depth;i>0;i--){
            res.append("--");
        }
        return res.toString();
    }
}

平衡二叉树

AVL 红黑树

算法第七章

集合

集合的时间复杂度

增,查,删O(h) h是二分搜索树的高度

平均O(logn)

有序集合和无序集合

有序集合中的元素具有顺序性

无需集合中的元素没有顺序性 —— 基于哈希表的表现

映射 Map

例子:字典(单词) 名册(身份证号) 车辆管理 数据库(id)

有序映射和无序映射

有序映射(键具有顺序性) —— 基于搜索树的实现
public class BSTMap<K extends Comparable,V> implements Map<K,V> {

    private class Node{
        public K key;
        public V value;
        public Node left,right;
        public Node(K key,V value){
            this.key=key;
            this.value=value;
            left=null;
            right=null;
        }
    }
    private Node root;
    private int size;

    public BSTMap() {
        this.root = null;
        this.size = 0;
    }

    @Override
    public void add(K key, V value) {
        root=add(root,key,value);
    }
    //向二分搜索树中添加新的元素(key,value))
    private Node add(Node node, K key, V value) {
        if(node==null){
            size++;
            return new Node(key,value);
        }
        if(key.compareTo(node.key)<0){
            node.left=add(node.left,key,value);
        }else if(key.compareTo(node.key)>0){
            node.right=add(node.right,key,value);
        }else{
            node.value=value;
        }
        return node;
    }
    private Node getNode(Node node,K key){
        if(node == null){
            return null;
        }
        if(key.compareTo(node.key) == 0){
            return node;
        }else if(key.compareTo(node.key) < 0){
            return getNode(node.left,key);
        }else{
            return getNode(node.right,key);
        }
    }

    @Override
    public V remove(K key) {
        Node node=getNode(root,key);
        if(node!=null){
            root=remove(root,key);
            return node.value;
        }
        return null;
    }
    private Node remove(Node node, K key) {
        if(node==null){
            return null;
        }
        //e<node.e 要删除的数小于当前数
        if(key.compareTo(node.key)<0){
            node.left=remove(node.left,key);
            return node;
        }else if(key.compareTo(node.key)>0){
            node.right=remove(node.right,key);
            return node;
        }else{
            //查找到需要删除的数
            //待删除节点左子树为空的情况,应该直接把删除节点右子树转接到该节点的位置
            if(node.left==null){
                Node rightNode=node.right;
                node.right=null;
                size--;
                return rightNode;
            }
            //待删除节点右子树为空的情况
            if(node.right==null){
                Node leftNode=node.left;
                node.left=null;
                size--;
                return leftNode;
            }

            //待删除节点左右子树均不为空的情况
            //找到比待删除节点大的最小节点,即待删除节点右子树的最小节点
            //用这个节点顶替待删除节点的位置
            Node successor=minimum(node.right);
            successor.right=removeMin(node.right);
            successor.left=node.left;
            node.left=node.right=null;
            return successor;
        }

    }

    //删除掉以node为根的二分搜索树中最小节点
    //返回删除节点后新的二分搜索树的根
    private Node removeMin(Node node){
        //删掉当前节点
        if(node.left==null){
            //如果node.right也等于null
            Node rightNode=node.right;
            node.right=null;
            size--;
            return rightNode;
        }
        node.left=removeMin(node.left);
        return node;
    }
    //返回以node为根的二分搜索树的最小值所在的节点
    private Node minimum(Node node) {
        if(node.left==null){
            return node;
        }
        return minimum(node.left);
    }
    @Override
    public boolean contains(K key) {
        return getNode(root,key) != null;
    }

    @Override
    public V get(K key) {
        Node node=getNode(root,key);
        return node == null ? null : node.value;
    }

    @Override
    public void set(K key, V newValue) {
        Node node = getNode(root,key);
        if(node == null){
            throw new IllegalArgumentException(key+"doesn't exist!");
        }
        node.value=newValue;
    }

    @Override
    public int getSize() {
        return this.size;
    }

    @Override
    public boolean isEmpty() {
        return this.size==0;
    }
}

无序映射 --------- 基于链表的实现

public class LinkedListMap<K,V> implements Map<K,V> {
    private class Node{
        public K key;
        public V value;
        public Node next;

        public Node(K key,V value,Node next){
            this.key=key;
            this.value=value;
            this.next=next;
        }
        public Node(K key){
            this(key,null,null);
        }
        public Node(){
            this(null,null,null);
        }
        @Override
        public String toString(){
            return this.key+":"+this.value;
        }
    }
    private Node dummyHead;
    private int size;

    public LinkedListMap() {
        this.dummyHead = new Node();
        this.size = 0;
    }

    private Node getNode(K key){
        Node cur=dummyHead.next;
        while (cur!=null){
            if(cur.key.equals(key)){
                return cur;
            }
            cur=cur.next;
        }
        return null;
    }
    @Override
    public void add(K key, V value) {
        Node node=getNode(key);
        if(node==null){
            //添加在头部
            dummyHead.next=new Node(key,value,dummyHead.next);
            size++;
        }else{
            node.value=value;
        }
    }

    @Override
    public V remove(K key) {
        //查找元素,查找到则退出
        Node prev=dummyHead;
        while (prev.next!=null){
            if(prev.next.key.equals(key)){
                break;
            }
            prev=prev.next;
        }
        if(prev.next!=null){
            Node delNode=prev.next;
            prev.next=delNode.next;
            delNode.next=null;
            return delNode.value;
        }
        return null;
    }

    @Override
    public boolean contains(K key) {
        return getNode(key)!=null;
    }

    @Override
    public V get(K key) {
        Node node=getNode(key);
        return node==null?null:node.value;
    }

    @Override
    public void set(K key, V newValue) {
        Node node=getNode(key);
        if(node==null){
            throw new IllegalArgumentException(key+"doesn't exist!");
        }
        node.value=newValue;
    }

    @Override
    public int getSize() {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }
}

无序映射(没有顺序性) —— 基于哈希表的实现

第八章

优先队列

定义:出队顺序和入队顺序无关,和优先级相关
动态排序队列 (ai 优先队列取对应的敌人)

普通线性

顺序线性
在这里插入图片描述

堆(二叉堆)

一个堆本身也是一棵树

二叉堆是一颗完全二叉树 (如果最后一层节点不够,从左到右排序)
堆中某个节点的值总是不大于其父节点的值

完全二叉树 : 把元素顺序排列成树的形状

在这里插入图片描述

通过上浮完成堆的性质(当前节点小于其父节点)

下沉取出数据

Replace: 取出最大元素后,再放入一个新的元素

Heapify: 将任意数组整理成堆的形状(只要最后一个非叶子节点不断siftDown)

堆的代码表示:
public class MaxHeap<E extends Comparable<E>>  {
    private Array<E> data;
    public MaxHeap(int capacity){
        data=new Array<>(capacity);
    }
    public MaxHeap(){
        data=new Array<>();
    }
    //返回堆中的元素个数
    public int size(){
        return data.getSize();
    }
    //返回一个布尔值,表示堆中是否为空
    public boolean isEmpty(){
        return data.isEmpty();
    }
    public int parent(int index){
        if(index == 0){
            throw new IllegalArgumentException("0 doesn't have parent");
        }
        return (index - 1)/2;
    }

    //返回完全二叉树的数组表示中,一个索引所表示的元素左孩子节点的索引
    private int leftChild(int index){
        return index * 2 + 1;
    }
    //返回完全二叉树的数组表示中,一个索引所表示的元素右孩子节点的索引
    private int rightChild(int index){
        return index * 2 + 2;
    }
    //向堆中添加元素
    public void add(E e){
        data.addLast(e);
        siftUp(data.getSize()-1);
    }

    private void siftUp(int k) {
        while (k>0 && data.get(parent(k)).compareTo(data.get(k)) < 0){
             data.swap(k,parent(k));
        }
    }
    public E findMax(){
        if(data.getSize() == 0){
            throw new IllegalArgumentException("Can not findMax when heap is empty");
        }
        return data.get(0);
    }
    public E extractMax(){
        E ret=findMax();
        data.swap(0,data.getSize() - 1);
        data.removeLast();
        siftDown(0);

        return ret;
    }

    private void siftDown(int k) {
        while (leftChild(k) < data.getSize()){
             int j=leftChild(k);
             if(j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0){
                j=rightChild(k);
                //data[j] 是 leftChild 和 rightChild 中的最大值
            }
             if(data.get(k).compareTo(data.get(j)) >= 0){
                 break;
             }
             data.swap(k,j);
             k=j;
        }
    }

    public static void main(String[] args) {
        int n = 1000000;

        MaxHeap<Integer> maxHeap = new MaxHeap<>();
        Random random=new Random();
        for (int i = 0;i < n;i ++){
            maxHeap.add(random.nextInt(Integer.MAX_VALUE));
        }
        int[] arr = new int[n];
        for (int i =0 ; i < n;i++){
            arr[i] = maxHeap.extractMax();
        }
        System.out.println(arr[0]);
    }
    public E replace(E e){
        E ret=findMax();
        data.set(0,e);
        siftDown(0);
        return ret;
    }
    public MaxHeap(E[] arr){
        data=new Array<>(arr);
        for (int i=parent(arr.length - 1);i >= 0;i--){
            siftDown(i);
        }
    }

算法第九章

线段树

m次染色后 我们可以看到多少种颜色

染色操作(更新区间)

查询操作(查询区间)
在这里插入图片描述
线段树不是完全二叉树

线段树是平衡二叉树(最大深度和最小深度差只能为1)

堆也是平衡二叉树

对区间进行操作,可以使用线段树

代码
public class SegmentTree<E> {
    private E[] tree;
    private E[] data;
    private Merger<E> merger;
    public SegmentTree(E[] arr,Merger<E> merger){
        //创建一个与构造参数数组大小相同的成员变量数组
        //将构造参数数组中的值传入成员变量数组
        //对tree数组赋值 大小为4倍的arr.length

        this.merger=merger;//用来表示两个区间如何融合
        data=(E[])new Object[arr.length];
        for (int i=0;i<arr.length;i++){
            data[i]=arr[i];
        }
        tree= (E[]) new Object[4*arr.length];
        buildSegmentTree(0,0,data.length-1);
    }

    private void buildSegmentTree(int treeIndex,int l,int r) {
        //应考虑使用递归创建线段树,需要当前索引,以及区间范围
        //递归考虑结束条件为递归到底
        //如果没有递归到底,即当前索引一定有左右孩子,创建线段树的左右子树以及左右子树的区级范围
        //上一级为下一级节点之和
        if(l == r){
            tree[treeIndex] = data[l];
            return;
        }
        int leftTreeIndex=leftChild(treeIndex);
        int rightTreeIndex=rightChild(treeIndex);

        int mid = (l + r) / 2;
        buildSegmentTree(leftTreeIndex,l,mid);
        buildSegmentTree(rightTreeIndex,mid+1,r);

        tree[treeIndex] = merger.merge(tree[leftTreeIndex] , tree[rightTreeIndex]);

    }

    public void set(int index,E e){
        if(index < 0 || index >= data.length){
            throw new IllegalArgumentException("Index is illegal");
        }
        data[index]=e;
        set(0,0,data.length - 1,index,e);
    }

    private void set(int treeIndex, int l, int r, int index, E e) {
        //遍历所有的节点,找到符合的节点并更新
        if(l == r){
            tree[treeIndex] = e;
            return;
        }

        //计算出所需要的左中右节点
        int mid = l+(r + l) / 2;
        int leftTreeIndex=leftChild(treeIndex);
        int rightTreeIndex=rightChild(treeIndex);
        //根据index的索引,去对应区间,直到找到该值。
        if(index >= mid+1){
            set(rightTreeIndex,mid + 1,r,index,e);
        }else //index <= mid
        {
            set(leftTreeIndex,l,mid,index,e);
        }
        //对线段树的区间的值进行更新。
        tree[treeIndex] = merger.merge(tree[leftTreeIndex],tree[rightTreeIndex]);
    }


    public E query(int queryL,int queryR){
        //对传入的值进行有效区级查询,分别有有效值校验以及r必须大于l
        if(queryL<0||queryL>=data.length||
           queryL<0||queryR>=data.length||
           queryL>queryR){
            throw new IllegalArgumentException("Index is illegal.");
        }
        return query(0,0,data.length-1,queryL,queryR);
    }
    //在以treeID为根的线段树中 l-r 的范围里,搜索区级区级(qeryL...queryR)的值
    private E query(int treeIndex, int l, int r,int queryL,int queryR) {
         //结束条件为l和r的信息与用户想要查找的queryL和queryR重合
        if(l == queryL && r == queryR){
            return tree[treeIndex];
        }
        //获取以treeID为根的线段是的左右子树节点,以及中间数
        int mid = l + (r-l) / 2;
        int leftTreeIndex = leftChild(treeIndex);
        int rightTreeIndex=rightChild(treeIndex);

        //如果搜索区间在左子树,右子树,或者都有应该怎么办
        if(queryL >= mid + 1){
            return query(rightTreeIndex,mid + 1,r,queryL,queryR);
        }else if(queryR<=mid){
            return query(leftTreeIndex,l,mid,queryL,queryR);
        }

        E leftResult = query(leftTreeIndex, l, mid, queryL, queryR);
        E rightResult=query(rightTreeIndex,mid + 1,r,mid+1,queryR);
       return merger.merge(leftResult,rightResult);
    }

    public E get(int index){
        //判断当前索引是否合法
        //返回索引所在位置的成员变量数组的值
        if(index < 0 || index >= data.length){
            throw new IllegalArgumentException("Index is illegal");
        }

        return data[index];
    }
    private int leftChild(int index){
        return 2*index+1;
    }
    private int rightChild(int index){
        return 2*index+2;
    }
    @Override
    public String toString(){
        StringBuilder res=new StringBuilder();
        res.append("[");
        for (int i=0;i<tree.length;i++){
            if(tree[i]!=null){
                res.append(tree[i]);
            }else {
                res.append("null");
            }
           /* if(i!=tree.length-1){

            }*/
        }
        return res.toString();
    }
   /* public static void main(String[] args) {
        Integer[] nums={-2,0,3,-5,2,-1};
        SegmentTree<Integer> segmentTree=new SegmentTree<>(nums, new Merger<Integer>() {
            @Override
            public Integer merge(Integer a, Integer b) {
                //求和返回a+b 或者max(a,b)
                return a + b;
            }
        });
        System.out.println(segmentTree.query(0,2));
    }*/
}

第十章

Trie (多叉树)

专门真正给字典设计的数据结构(专门处理字符串)

时间复杂度为O(w) w为查询单词的长度

将字符串拆开以字母为单位

对于. 需要遍历所有的可能

trie的局限性:空间 改善:压缩字典树,把单链多个字符合并。

​ 三分搜索树 <d ==d >d

public class Trie {
    private class Node{
        public boolean isWord;
        public TreeMap<Character,Node> next;
        public Node(boolean isWord){
            this.isWord=isWord;
            next=new TreeMap<>();
        }

        public Node(){
            this(false);
        }
    }
    private Node root;
    private int size;
    public Trie(){
        root=new Node();
        size=0;
    }
    //获得Trie中存储的单词数量
    public int getSize(){
        return size;
    }
    //向Trie中添加一个新的单词word
    public void add(String word){
        Node cur=root;
        for (int i=0;i<word.length();i++){
            char c=word.charAt(i);
            //将字符添加到节点,如果节点中没有这个字符
            if(cur.next.get(c) == null){
                cur.next.put(c,new Node());
            }
            //将当前节点跳到下一个节点
            cur = cur.next.get(c);
        }

        if(!cur.isWord){
            cur.isWord = true;
            size++;
        }
    }

    //查询单词word是否在trie中
    public boolean contains(String word){
        //根据字符顺序,如果全部便利到,并且isWord为true,则返回包含该单词
        Node cur=root;
        for (int i = 0;i < word.length();i++){
            char c=word.charAt(i);
            if(cur.next.get(c) == null){
                return false;
            }
            //来到了这个字符所在的节点
            cur=cur.next.get(c);
        }
        //如果该节点isWord为true,则true
        return cur.isWord;
    }

    public boolean match(String word){
        return match(root,word,0);
    }
    //查询单词word是否在trie中
    private boolean match(Node node,String word,int index){
        //如果index与字符长度一致,且当前是一个单词,返回true;
        //对所传入的字符进行匹配,如果不为.,匹配成功后进入下一个节点,如果为.,递归遍历接下来的所有可能,匹配到返回true
        if(index == word.length()){
            return node.isWord;
        }
        char c= word.charAt(index);
        if(c != '.'){
            if(node.next.get(c) == null){
                return false;
            }
            return match(node.next.get(c),word,index+1);
        }else {
            for (char nextChar: node.next.keySet()){
                if(match(node.next.get(nextChar),word,index+1)){
                    return true;
                }
            }
            return false;
        }
    }
    //查找是否在trie中有单词以prefix为前缀
    public boolean isPrefix(String prefix){
        //查找有没有这个前缀节点就行
        Node cur=root;
        for (int i=0;i<prefix.length();i++){
            char c=prefix.charAt(i);
            if(cur.next.get(c) == null){
                return false;
            }
            cur = cur.next.get(c);
        }
        return true;
    }

}

第十一章

并查集

一种孩子指向父亲的数据结构

并查集可以很好看出来网络中节点间的连接状态

​ 网络是一个抽象的概念:用户之间形成的网络

连接问题和路径问题

在这里插入图片描述
每一个元素,看做是一个节点

在这里插入图片描述

基于size的优化,有可能节点多的深度比较小

提出 基于rank的优化。

路径压缩 :

路径压缩2 :直接指向根节点 (复杂度近乎是O(1))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值