1. 队列
1.1 队列的概述
队列是一种基于先进先出(FIFO)的数据结构,是一种只能在一端进行插入,在另一端进行删除操作的特殊线性表。
它按照先进先出的原则存储数据,先进入的数据,在读取时先被读出来
1.2 队列的API设计
类名 | Queue |
---|---|
构造方法 | Queue():创建Queue对象 |
成员方法 | 1. public boolean isEmpty():判断队列是否为空,时返回true,否返回false 2. public int size():获取队列中元素的个数 3. public T dequeue():从队列中拿出一个元素 4. public void enqueue(T t):往队列中插入一个元素 |
成员变量 | 1. private Node head:记录首节点 2. private int N:当前栈的元素个数 3. private Node last:记录最后一个节点 |
成员内部类 | private class Node:节点类 |
1.3 队列的实现
package com.renexdemo.linear;
import java.util.Iterator;
// 队列
public class Queue<T> implements Iterable<T> {
private Node head;
private Node last;
private int N;
// 节点类
private static class Node<T>{
public T item;// 存储元素
public Node next;// 指向下一个节点
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
// 初始化构造
public Queue() {
this.head = new Node(null,null);
this.last = null;
this.N = 0;
}
// 判断为空
public boolean isEmpty(){
return N==0;
}
// 获得队列的长度
public int size(){
return N;
}
// 填入一个元素
public void enqueue(T t){
// 当前尾结点last为null
if (last == null){
last = new Node(t,null);
head.next = last;
}else
{
// 当前尾结点last不为null
Node oldLast = last;
last = new Node<>(t, null);
oldLast.next = last;
}
// 元素个数+1
N++;
}
// 取出一个元素
public T dequeue(){
if (isEmpty()){
return null;
}
Node oldFirst = head.next;
head.next = oldFirst.next;
N--;
// 如果队列中没有元素了,那么需要重置last=null
if (isEmpty()){
last = null;
}
return (T) oldFirst.item;
}
@Override
public Iterator<T> iterator() {
return new QIterable();
}
private class QIterable implements Iterator{
private Node n;
public QIterable() {
this.n = head;
}
@Override
public boolean hasNext() {
return n.next!=null;
}
@Override
public Object next() {
n = n.next;
return n.item;
}
}
}
2. 无序符号表
2.1 符号表的概述
符号表最重要的目的就是将一个键和一个值联系起来,符号表能够将存储的数据元素是一个键和一个值共同组成的键值对数据,我们可以根据键来查找对应的值,说白了,就是以键值对形式存储
符号表中,键具有唯一性
符号表在实际生活中的使用常见是非常广泛的,见下表:
应用 | 查找目的 | 键 | 值 |
---|---|---|---|
字典 | 找出单次的释义 | 单词 | 释义 |
图书索引 | 找出某个术语相关的页码 | 术语 | 一串页码 |
网络搜索 | 找出某个关键字对应的网页 | 关键字 | 网页名称 |
2.2 符号表API设计
节点类:
类名 | Node<Key,Value> |
---|---|
构造方法 | Node(Key key,Value value,Node next):创建Node对象 |
成员变量 | 1. public Key key:存储键 2. public 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 value):向符号表中插入一个键值对 3. public void delete(Key key):删除键为key的键值对 4. public int size():获取符号表的大小 |
成员变量 | 1. private Node head:记录首节点 2. private int N:记录符号表中键值对的个数 |
3. 有序符号表
当需要实现排序功能时,那么无序符号表将无法实现,这时就需要有序符号表
3.1 实现代码
package com.renexdemo.symbol;
// 有序符号表
public class OrderSymbolTable<Key extends Comparable<Key>,Value> {
private Node head;
private int N;
// 节点类
private class Node{
public Key key;
public Value value;
public Node next;
public Node(Key key, Value value, Node next) {
this.key = key;
this.value = value;
this.next = next;
}
}
// 初始化类
public OrderSymbolTable() {
this.head = new Node(null,null,null);
this.N = 0;
}
// 获得当前符号表中元素的个数
public int size(){
return N;
}
// 往符号表中添加键值对
public void put(Key key,Value value){
// 定义两个Node变量,分别记录当前节点和当前节点的上一个节点
Node curr = head.next;
Node pre = head;
while (curr != null && key.compareTo(curr.key)>0){
// 变换当前节点和前一个节点即可
pre = curr;
curr = curr.next;
}
// 如果当前节点curr的key和要插入的key一样,则替换
if (curr != null && key.compareTo(curr.key) ==0){
curr.value = value;
return;
}
// 如果不一样,把新节点插入到curr之前
Node node = new Node(key, value, curr);
pre.next = node;
// 元素个数+1
N++;
}
// 删除符号表中键位key的键值对
public void delete(Key key){
// 找到键位key的节点,把该节点从链表中删除
Node n = head;
while (n.next != null){
// 判断n节点的键是否为key,如果是则替换
if (n.next.key.equals(key)){
n.next = n.next.next;
N--;
return;
}
// 变换n
n = n.next;
}
}
// 从符号表中获得键位key的对应值
public Value get(Key key){
// 找到键位key的节点,把该节点从链表中删除
Node n = head;
while (n.next != null){
// 变换n
n = n.next;
// 判断n节点的键是否为key,如果是则替换
if (n.key.equals(key)){
return n.value;
}
}
return null;
}
}
4. 注意
如果有初上手小白看代码,请别想的那么复杂。删除或添加(弹栈、压栈、入队、离队这种)可以说就是更改了指向的下一个节点。