一、什么是符号表
之前学的数据结构,如链表,都是存储单个元素的,那字典这种类型的呢?
这个时候就可以使用符号表了,符号表就是描述键值对类型的数据结构的。
二、思路
之前记录过链表的实现是通过节点连接的,当时每个节点只有一个元素和一个指向下个节点的地址域,如果要实现符号表,也可以使用节点连接,只是此时的节点需要存储两个元素和一个地址域,这两个元素一个是key,一个是value。
三、Java代码实现
package mypackage;
import java.util.Iterator;
//<key,value>泛型表示类型
class SymbolTable<key,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已经存在,覆盖value,
// 如果不存在,让首节点指向新节点,新节点指向原来的新节点
public void put(key key,value value){
// 判断如果存在key直接替换
Node node=head;
while(node.next!=null){
node=node.next;
if (node.key==key){
node.value=value;
// 替换完了直接结束方法
return;
}
}
// 如果不存在,创建新节点,让head指向新节点,新节点指向之前的第一个节点
// 并且N++
Node newnode=new Node(key,value,null);
Node oldfirst = head.next;
head.next=newnode;
newnode.next=oldfirst;
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.value;
}
}
}
//测试
public class MyJava {
public static void main(String[] args) {
// 创建一个符号表
SymbolTable<Integer,String> symbolTable = new SymbolTable<>();
// 添加节点节点
symbolTable.put(1,"刘备");
symbolTable.put(2,"关羽");
symbolTable.put(3,"张飞");
symbolTable.put(4,"赵云");
symbolTable.put(5,"黄忠");
symbolTable.put(6,"马超");
System.out.print("添加元素后符号表的值为(和添加顺序是相反的):");
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());
}
}
结果: