数据结构java第四天

符号表

符号表最主要的目的就是将一个键和一个值联系起来,符号表能够将存储的数据元素为一个键和一个值共同组成的键值对数据,我们可以根据键来查找对应的值。
结点类:

类名Node<Key, Value>
构造方法Node(Key key, Value value, Node next)创建Node对象
成员变量1.public Key key;存储键
2.publicj Value value存储值
3.public Node next;存储下一个结点

符号表:

类名SymbolTable<Key, Value>
构造方法SymbolTable():创建SymbolTable对象
成员方法1.public Value get(Key key)根据key找到对应的值
2.public void put(Key key, Value val) 向符号表中插入一个键值对
3.public void delete(Key key)删除键为key的键值对
4.public int size()获取符号表的大小
成员变量1.private Node head;记录首结点
2.private int N记录符号表中键值对的个数
package Symbol;

import org.w3c.dom.Node;

import javax.management.NotificationEmitter;
import java.util.Iterator;

public class SymbolTable <Key, Value> implements Iterable{
    //记录首结点
    private Node head;
    //记录符号表长度
    private int N;

    public class Node{
        public Key key;
        public Value value;
        public Node next;
        public Node(Key key, Value value, Node next){
            this.key = key;
            this.next = next;
            this.value = value;
        }
    }

    public SymbolTable(){
        head = new Node(null, null, null);
        N = 0;
    }

    //判断当前符号表是否为空
    public boolean isEmpty(){
        return N==0;
    }

    //获取符号表中键值对的个数
    public int size(){
        return N;
    }

    //往符号表中插入键值对
    public void put(Key key, Value value){
        //符号表中已经存在键为key的键值对
        Node n = head;
        while (n.next != null){
            n = n.next;
            if (n.key.equals(key)){
                n.value = value;
                return;
            }
        }
        Node newNode = new Node(key, value, null);
        n.next = newNode;
        N++;
    }

    //删除符号表中键为key的键值对
    public Node delete(Key key){
        Node n = head;
        while (n.next != null){
            if (n.next.key.equals(key)) {
                Node delNode = n.next;
                n.next = delNode.next;
                N--;
                return delNode;
            }
            n = n.next;
        }
        return null;
    }

    //找到符号表中key对应的值
    public Value get(Key key){
        Node n = head;
        while (n.next != null){
            n = n.next;
            if (n.key.equals(key)){
                return n.value;
            }
        }
        return null;
    }

    @Override
    public Iterator iterator() {
        return new STIterator();
    }

    public class STIterator implements Iterator{
        private Node n;

        public STIterator(){
            this.n = head;
        }
        @Override
        public boolean hasNext() {
            return n.next != null;
        }

        @Override
        public Object next() {
            n = n.next;
            return n.value;
        }
    }
}

有序符号表的实现

public void put(Key key, Value value){
        //符号表中已经存在键为key的键值对
        Node pre = head;
        Node newNode;
        Node curr = head.next;
        while (curr != null && curr.key.compareTo(key) < 0){
            pre = curr;
            curr =curr.next;
        }
        if (curr != null && curr.key.equals(key)){
            curr.value = value;
            return;
        }
        newNode = new Node(key, value, curr);
        pre.next = newNode;
        N++;
    }

树的基本定义

二叉查找树的创建

结点类

类名Node<Key, Value>
构造方法Node(Key key, Value value, Node left, Node right) 创建Node对象
成员变量1.public Node left: 记录左子节点
2.public Node right 记录右子结点
3.public Key ket; 存储键
4. public Value value; 存储值

二叉查找树API设计

类名BinaryTree<Key extends Comparable, Value value>
构造方法public BinaryTree():创建binarytree对象
成员变量1.private Node root 记录根结点
2.private int N;记录树中的元素个数
成员方法1.public void put(Key key, Value value) 向树中插入一个键值对
2.private Node put(Node x, Key key, Value val) 给指定的树x上添加一个键值对,并返回添加后的新树
3.public Value get(Key key) 根据key从树中找出对应的值
4.private Value get(Node x, Key key) 从指定的树x中,找出key对应的值
5.public void delete(Key key):根据key,删除树中对应的键值对
6.private Node delete(Node x,j Key key) 删除指定树x上的键为key的键值对,并返回删除后的新树
7.public int size()获取树中元素的个数
package Tree;

public class BinaryTree<Key extends Comparable<Key>, Value> {
    //记录根结点
    private Node root;
    //记录树中元素的个数
    private int N;
    private class Node{
        public Key key;
        public Value value;
        public Node left;
        public Node right;
        public Node(Key key, Value value, Node left, Node right){
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
        }
    }

    //初始化一颗树
    public BinaryTree(){
        root = null;
        N = 0;
    }

    //获取树中的元素的个数
    public int size(){
        return N;
    }

    public void put(Key key, Value value){
        root = put(root,key,value);
    }

    //向指定的子树中添加key-value,并返回添加元素后的树
    public Node put(Node x, Key key, Value value){
        //如果子树为空
        if (x == null){
            N++;
            return new Node(key, value, null, null);
        }
        //如果子树不为空
        //比较x结点的键和参数key的大小
        int cmp = x.key.compareTo(key);
        //如果key小于x结点的键,则继续找x结点的左子树
        if (cmp > 0){
//            if (x.left == null){
//                Node n = new Node(key, value, null, null);
//                x.left = n;
//                N++;
//                return root;
//            }
            x.left = put(x.left, key, value);
        }
        //如果key大于x结点的键,则继续找x结点的右子树
        else if (cmp < 0) {
//            if (x.right == null){
//                Node n = new Node(key, value, null, null);
//                x.right = n;
//                N++;
//                return root;
//            }
            x.right = put(x.right, key, value);
        }
        //如果key等于x结点的键,则替换x结点的值为value
        else {
            x.value = value;
        }
        return x;
    }

    //查询树中指定key对应的value
    public Value get(Key key){
        Value value = get(root, key);
        return value;
    }

    //查询指定的树x中,key对应的value
    public Value get(Node x, Key key){
        if (x == null){
            return null;
        }
        int cmp = key.compareTo(x.key);
        if (cmp < 0){
            return get(x.left, key);
        }
        else if (cmp > 0){
            return get(x.right, key);
        }
        else return x.value;
    }

    //删除树中key对应的value
    public void delete(Key key){
        delete(root, key);
    }

    //删除指定树x中的key对应的value,并返回删除后的新树
    public Node delete(Node x, Key key){
        //x树为null
        if (x == null){
            return null;
        }
        //x树不为null
        int cmp = key.compareTo(x.key);
        if (cmp < 0){
            x.left = delete(x.left, key);
        }
        else if (cmp > 0){
            x.right = delete(x.right, key);
        }
        else {
            N--;
            //如果key等于x结点的键,完成真正的删除结点的动作,要删除的结点为x
            //寻找右子树的最左结点
            //如果右子树为空
            if (x.right == null){
                return x.left;
            }
            //如果左子树为空
            if (x.left == null){
                return x.right;
            }
            Node minNode = x.right;
            Node minParNode = x.right;
            while (minNode.left != null){
                minParNode = minNode;
                minNode = minNode.left;
            }
            //删除右子树的最小结点
            minParNode.left = null;
            //将minNode结点放入
            minNode.left = x.left;
            minNode.right = x.right;
            x = minNode;
        }
        return x;
    }
}

查找二叉排序树中最小的键

public Key min()找出树中最小的键
private Node min(Node x)找出指定树x中,最小键所在的结点
//查找整个树中最小的键
    public Key min(){
        return min(root).key;
    }
    
    //查找指定树x中最小键所在的结点
    public Node min(Node x){
        if (x.left != null){
            return min(x.left);
        }
        else return x;
    }
    
    //查找整个树中最大键
    public Key max(){
        return max(root).key;
    }
    
    //查找x树中最大键所在的结点
    public Node max(Node x){
        if (x.right != null){
            return max(x.right);
        }
        else return x;
    }

二叉树的基础遍历

前序遍历

public Queue preErgodic()使用前序遍历,获取整个树中的所有键
public void preErgodic(Node x, Queue keys)使用前序遍历,把指定树x中的所有键放入到keys队列中

实现步骤:
1.把当前结点的key放入到队列中去
2.找到当前结点的左子树,如果不为空,遍历递归左子树
3.找到当前结点的右子树,如果不为空,递归遍历右子树
前序遍历

//获取整个树中所有的键
    public Queue<Key> preErgodic(){
        Queue<Key> keys = new Queue<>();
        preErgodic(root, keys);
        return keys;
    }

    //获取指定树x中的所有键,并且放在keys队列中
    private void preErgodic(Node x, Queue<Key> keys){
        if (x == null){
            return;
        }
        //把x结点的key放入keys中
        keys.enqueue(x.key);
        //递归遍历x结点的左子树
        if (x.left != null){
            preErgodic(x.left, keys);
        }
        //递归遍历x结点的右子树
        if (x.right != null){
            preErgodic(x.right, keys);
        }
    }

中序遍历

//中序遍历获取树中所有的键
    public Queue<Key> midErgodic(){
        Queue<Key> keys = new Queue<>();
        midErgodic(root, keys);
        return keys;
    }

    //中序遍历获取当前树x中的所有键,并且放在队列中
    private void midErgodic(Node x, Queue keys){
        if (x == null){
            return;
        }
        if (x.left != null){
            midErgodic(x.left, keys);
        }
        keys.enqueue(x.key);
        if (x.right != null){
            midErgodic(x.right, keys);
        }

    }

后序遍历

//使用后续遍历获取树中所有的键
    public Queue<Key> afterErgodic(){
        Queue<Key> keys = new Queue<Key>();
        afterErgodic(root, keys);
        return keys;
    }

    //使用后序遍历获取x树中所有的键
    public void afterErgodic(Node x, Queue<Key> keys){
        if (x == null){
            return;
        }
        if (x.left != null){
            afterErgodic(x.left, keys);
        }
        if (x.right != null){
            afterErgodic(x.right, keys);
        }
        keys.enqueue(x.key);
    }

层次遍历

//层次遍历
    public Queue<Key> layerErgodic(){
        //定义两个队列分别存储树中的键和树中的结点
        Queue<Key> keys = new Queue<>();
        Queue<Node> nodes = new Queue<>();
        nodes.enqueue(root);
        while (!nodes.isEmpty()){
            Node n = nodes.dequeue();
            keys.enqueue(n.key);
            if (n.left != null){
                nodes.enqueue(n.left);
            }
            if (n.right != null){
                nodes.enqueue(n.right);
            }
        }
        return keys;
    }

二叉树最大深度问题

API设计:

public int maxDepth()计算整个树的最大深度
private int maxDepth(Node x)计算指定树的最大深度
//获取整个树的最大深度
    public int maxDepth(){
        return maxDepth(root);
    }

    //获取当前树x的最大深度
    public int maxDepth(Node x){
        if (x == null){
            return 0;
        }
        int max = 0;
        int maxL = 0;
        int maxR = 0;
        //计算x结点左子树最大深度
        if (x.left != null){
            maxL = maxDepth(x.left);
        }
        //计算x结点右子树最大深度
        if (x.right != null){
            maxR = maxDepth(x.right);
        }
        //比较左子树和右子树最大深度,取最大值+1
        max = (maxL > maxR ? maxL : maxR) + 1;
        return max;
    }

折纸问题

请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后展开。此时折痕是凹下去的,即折痕凸起的方向指向纸条的背面。如果从纸条的下边向上连续对折两次,压出折痕后展开,此时有三条折痕,从上到下依次是下折痕,下折痕和上折痕。
给定一个输入参数n,代表纸条都从下边向上边连续对折n次,请从上到下打印所有折痕的方向。
例如: N = 1时,打印down;N = 0时,打印down down up
我们将对折后的纸张翻过来,让粉色朝下,这是把第一次对折产生的折痕看作是根结点,那第二次对折产生的下折痕是该节点的左子节点,而第二次对折产生的上折痕就是该结点的右子结点,这样我们就可以使用树型数据结构来描述对折后产生的折痕。
这棵树有这样的特点:
1.根结点为下折痕
2.每一个结点的左子结点为下折痕
3.每一个结点的右子结点为上折痕

package Test;

import Tree.Queue;

import java.security.PublicKey;

public class PaperFoldingTest {
    public static void main(String[] args){

        //模拟折纸过程产生树
        Node<String> root = creatTree(3);
        //遍历树,打印每个结点
        printTree(root);
    }

    //通过模拟对折N次纸产生树
    public static Node<String> creatTree(int N){
        //定义根结点
        Node<String> root = null;
        for (int i = 0; i < N; i++) {
            //第一次对折
            if (i == 0){
                root = new Node<String>("down", null, null);
                continue;
            }
            //不是第一次对折
            //定义一个辅助队列,通过一个层序遍历的思想,找到叶子结点,为叶子结点添加子节点
            Queue<Node> queue = new Queue<>();
            queue.enqueue(root);
            //循环遍历队列
            while (!queue.isEmpty()){
                //从队列中弹出一个结点
                Node n = queue.dequeue();
                //如果有左子结点,就将左子结点放入队列
                if (n.left != null){
                    queue.enqueue(n.left);
                }
                if (n.right != null){
                    queue.enqueue(n.right);
                }
                if (n.left == null && n.right == null){
                    Node<String> leftn = new Node<>("down", null, null);
                    Node<String> rightn = new Node<>("up", null, null);
                    n.left = leftn;
                    n.right = rightn;
                }
            }
        }
        return root;
    }

    //打印树中每个结点到控制台,使用中序遍历
    public static void printTree(Node<String> root){
        if (root == null){
            return;
        }
        Node n = root;
        if (n.left != null){
            printTree(n.left);
        }
        System.out.print(n.item + " ");
        if (n.right != null){
            printTree(n.right);
        }
    }

    //结点类
    private static class Node<T>{
        public T item;
        public Node left;
        public Node right;
        public Node(T item, Node left, Node right){
            this.item = item;
            this.left = left;
            this.right = right;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值