Python 每日一记241>>>Java有序符号表实现及key extends Comparable的理解

一、思路

上一篇文章,在添加元素时暴力的将其添加到head的后面,如果要根据key的顺序有序的添加怎么办?
我们在添加的时候循环判断key的大小即可,就是和循环到的节点的key比较,但是要比较的话,就得提供比较规则,这个时候就可以使用Comparable,让key extends Comparable,这样key就可以使用compareTo方法了。

二、Java代码实现

直接看put方法即可,其他不变

/**
 * 特别注意创建符号类时key extends Comparable,这样key就是可比较的
 * 就可以使用compareTo方法,
 * 另外需要注意,还要考虑到key已经存在的情况
 */


package mypackage;

import java.util.Iterator;

//<key,value>泛型表示类型
class SymbolTable<key extends Comparable,value> implements Iterable<value>{
    //记录头节点
    private Node head;
    //记录符号表的长度,即节点的个数
    private int N;

    //定义节点类,这一步至关重要
    //注意构造方法的参数有一个是next,这个类型是Node,正是我们定义的这个类Node
    //这样的话,我们每个节点就可以传入一个参数,next,然后用当前结点调用.next属性就可以获得下一个节点
    //这就是单项符号表链接的核心
    private class Node{
        //键、值和下一个节点项
        key key;
        value value;
        Node next;
        //构造方法
        public Node(key key, value value,Node next){
            this.key=key;
            this.value=value;
            this.next=next;
        }
    }

    //构造方法
    public SymbolTable(){
        //初始化头节点,初步的头节点的键值和下一个节点项都是null,节点个数为0
        //头节点的数据项本身就定义为null,他的作用只是指向符号表的第一个由数据的节点而已
        //尾节点的下一个节点项本身就定义为null,表示符号表的结束
        this.head=new Node(null,null,null);
        this.N=0;
    }

    //清空符号表,使得头节点不指向任何节点,且节点个数为0
    public void clear(){
        head.next=null;
        this.N=0;
    }

    //获取节点个数
    public int length(){
        return N;
    }

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

//    有序符号表只需要确保插入时有序即可
//    插入前循环遍历符号表,如果要插入的key较大,就继续向后循环,
//    直到待插入的key<=当前key,就找打了插入的位置
//    如果待插入的key==当前key,说明之前就存在key,直接替换
//    如果待插入的key<当前key,插入,让当前节点的前一个节点指向新节点,新节点指向当前节点
//    最后N++
    public void put(key key ,value value){
        Node prenode=head;
        Node curnode=head.next;
//        key.compareTo(curnode.key)>0,表示判断key大于curnode.key,成立就继续循环
        while (curnode!=null&&key.compareTo(curnode.key)>0){
            prenode=curnode;
            curnode=curnode.next;
        }
//        跳出循环表示找到了key<=当前key
//        如果key==当前key,直接替换
        if (curnode!=null&&key.compareTo(curnode.key)==0){
            curnode.value=value;
            return;
        }
//        如果key<当前key
        else {
//            新节点指向curnode,pre指向newnode,且N++
            Node newnode=new Node(key,value,curnode);
            prenode.next=newnode;
            N++;
        }

    }

//    根据删除键值对
    public void delete(key key){
        Node node=head;
        while(node.next!=null){
            node=node.next;
            if (node.key==key){
//                如果找到key。让head指向当前node的下一个节点
                head.next=node.next;
//              删除后,N--
                N--;
                return;
            }
        }
    }

//    查找值,循环遍历,如果找到key返回value
    public value get(key key){
        Node node=head;
        while(node.next!=null){
            node=node.next;
            if (node.key==key){
//                如果找到key。返回值
                return node.value;
            }
        }
//        循环完了还没找到,返回null
        return null;
    }

//    遍历
    @Override
    public Iterator iterator() {
        return new SIterator();
    }
    //    创建一个内部类实现Iterator接口
    public class SIterator implements Iterator {
        //        定义一个遍历的节点
        private Node n;
        public SIterator(){
//            初始化为0索引位置
            this.n=head;
        }
        //重写两个方法
        @Override
        public boolean hasNext() {
//            这个方法判断是否超出最大索引,如果超出会停止遍历
            return n.next!=null;
        }

        @Override
        public Object next() {
//            这个方法会遍历得每个节点
            n=n.next;
//            迭代处的格式为键:值
            return n.key+":"+n.value;
        }
    }
}



//测试
public class MyJava {
    public static void main(String[] args) {
//        创建一个符号表
        SymbolTable<Integer,String> symbolTable = new  SymbolTable<>();
//        添加节点节点,注意这里打乱循序的存,看最后是不是有序的
        symbolTable.put(3,"张飞");
        symbolTable.put(4,"赵云");
        symbolTable.put(1,"刘备");
        symbolTable.put(2,"关羽");
        symbolTable.put(5,"黄忠");
        symbolTable.put(6,"马超");

        System.out.print("添加元素后符号表的值为(和key的顺序是一样的):");
        for (String s:symbolTable){
            System.out.print(s+";");
        }
        System.out.println();
        System.out.println("元素个数:"+symbolTable.length());

//        替换了1
        symbolTable.put(1,"诸葛亮");
        System.out.println("替换后1处的元素是"+symbolTable.get(1));

//        删除
        symbolTable.delete(1);
        System.out.println("删除后元素个数为:"+symbolTable.length());

    }
}

结果:
在这里插入图片描述

三、key extends Comparable的理解

Comparable是一个接口,在我们的印象中,类继承extends类,类implements接口,接口extends接口,那么key只是一个泛型的占位符,后面extends Comparable,所以key是一个接口?其实这里的概念很模糊,以下截图自一篇文章:
在这里插入图片描述
因此,无论T是接口还是类,但是有一点必须要注意,那么就是T一定要实现了Comparable接口,才能使用比较方法,比如本文的Integar内部其实是实现了compareTo方法的。

发布了235 篇原创文章 · 获赞 24 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_44663675/article/details/105575271
今日推荐