写在前面
这篇博文主要是回顾了一下之前数据结构的知识,使用单链表与数组的方式分别实现了堆栈与队列。
逻辑结构与物理结构
逻辑结构顾名思义就是人们抽象出来的结构,通常包含
- 集合结构:集合结构的集合中任何两个数据元素之间都没有逻辑关系,组织形式松散
- 线性结构:数据结构中线性结构指的是数据元素之间存在着“一对一”的线性关系的数据结构
- 图结构
- 树状结构:树状结构是一个或多个节点的有限集合
其中习惯分为两类——线性结构与非线性结构(集合结构、树、图)
而物理结构就是数据实际的存储结构包括顺序存储结构(数组)与链式存储结构(链表等),因此分别采用两种存储结构实现栈与队列。
栈与队列
堆栈是一种先进后出的结构,生活中的例子似乎不太多,不过还是有一些例子,比如一摞碗,每次取的时候总是取得最上边的碗,最下边的碗总是最后一个被取走。队列是一种先进先出的结构,生活中例子很多,最常见的就是排队了,排在前边的人先被服务,后边的人最后被服务。
节点结构与接口声明
每个节点有数据域与指针域,栈与队列类实现了添加、弹出、求长度、判断为空等接口方法
节点结构
//节点类
class Node{
private Object data;
public Node next;
public Node(Object data){
this.data=data;
}
public Node(){}
@Override
public String toString() {
return String.valueOf(data);
}
}
接口声明
interface Stack{ /*堆栈接口*/
public void push(Node node) throws Exception; //压入堆栈
public Node pop() throws Exception; //弹出堆栈
public int Length(); //计算堆栈元素个数
public int indexOf(Node node) throws Exception; //求元素索引1
public boolean isEmpty(); //判断堆栈是否为空
}
interface Queue{ //队列接口声明
public int Length(); //队列长度
public boolean isEmpty(); //队列是否为空
public int indexOf(Node node) throws Exception; //求某个元素索引
public void add(Node node) throws Exception; //添加元素
public Node pop() throws Exception; //弹出元素
}
堆栈
链表结构(头插法)
//堆栈类(单链表-头插法)
class StackList implements Stack{
private Node head=null;
public StackList(){
head=new Node(); //初始化头指针
}
@Override
public void push(Node node) {
Node temp=head.next;
head.next=node;
node.next=temp;
}
@Override
public int indexOf(Node node) throws Exception{
if (isEmpty()) { //队列为空报错
throw new Exception("当前队列为空,请先添加元素!");
}
int i=0; //循环计数器
boolean isMatch=false; //是否匹配成功标志
Node temp=head.next;
while (temp!=null){
if (temp==node){ //地址相同即为相同对象
isMatch=true;
break;
}
temp=temp.next;
i++;
}
if (!isMatch){
throw new Exception("当前队列没有该元素!");
}
return i;
}
@Override
public Node pop() throws Exception{
if (head.next==null){
throw new Exception("当前堆栈为空!");
}
Node temp=head.next;
head.next=head.next.next;
return temp;
}
@Override
public int Length() {
int i=0;
Node temp=head.next;
while (temp!=null){
temp=temp.next;
i++;
}
return i;
}
@Override
public boolean isEmpty() {
return head.next==null;
}
}
数组结构
//堆栈类(数组实现)
class StackArray implements Stack{
private int size=0; //当前堆栈中元素个数
private Node[] head=null; //数组首指针
public StackArray(int maxsize){
head=new Node[maxsize];
}
@Override
public void push(Node node) throws Exception {
if (size>=head.length){
throw new Exception("堆栈已满!");
}
head[size++]=node;
}
@Override
public Node pop() throws Exception {
if (isEmpty())
throw new Exception("堆栈为空!");
return head[--size];
}
@Override
public int Length() {
return size;
}
@Override
public int indexOf(Node node) throws Exception {
int i=0; //循环标志
boolean isMatch=false; //查找成功标志
for (;i<=size;i++){
if (head[i]==node){
isMatch=true;
break;
}
}
if (!isMatch)
throw new Exception("该元素不存在!");
return i;
}
@Override
public boolean isEmpty() {
return size==0;
}
}
队列
链表结构(尾插法)
//队列类(单链表实现-尾插法)
class QueueList implements Queue {
private Node head;
public QueueList(){
head=new Node();
}
//计算队列长度(不包含头节点)
public int Length(){
int i=0;
Node temp=head.next;
while (temp!=null){
temp=temp.next;
i++;
}
return i;
}
//队列是否为空
public boolean isEmpty(){
return head.next==null;
}
//查找节点位置索引
public int indexOf(Node node) throws Exception{
if (isEmpty()) { //队列为空报错
throw new Exception("当前队列为空,请先添加元素!");
}
int i=0; //循环计数器
boolean isMatch=false; //是否匹配成功标志
Node temp=head.next;
while (temp!=null){
if (temp==node){ //地址相同即为相同对象
isMatch=true;
break;
}
temp=temp.next;
i++;
}
if (!isMatch){
throw new Exception("当前队列没有该元素!");
}
return i;
}
//添加节点
public void add(Node node) throws Exception{
Node temp=head;
while (temp.next!=null){
temp=temp.next;
if (temp==node){
throw new Exception("该元素已经添加过!");
}
}
temp.next=node;
}
//弹出节点
public Node pop() throws Exception{
Node tempNode=null;
if (isEmpty()){
throw new Exception("队列为空!");
}else {
tempNode=head.next;
head.next=head.next.next;
}
return tempNode;
}
}
数组结构(循环数组)
在使用数组实现队列时容易形成假满现象,设想一下一个数组里元素为满的情况下从数组首元素开始出队列,直到剩下最后一个元素,若此时需要添加新的元素因为尾部已经没有空间,所以造成了空间浪费,因而采用循环数组的形式实现。
实现的方法主要是下一个位置对数组长度求余,比如数组长度为5,当前数组最后一个位置刚填入一个元素,那么下次的位置应该为0号位置(5%5=0)。
//队列类(循环数组实现)
class QueueArray implements Queue{
private final int Length;
private Node[] head=null;
//数组结构时实现循环队列需要此变量,链表结构不需要
private int front; //队首指针
private int rear; //队尾指针
public QueueArray(int length){
Length=length;
head=new Node[Length];
//队首队尾都指向0号位置
front=0;
rear=0;
}
@Override
public int Length() {
int i=0,count=0;
while (i<this.Length){
if (head[i]!=null){
count++;
}
i++;
}
return count;
}
@Override
public boolean isEmpty() {
return front==rear;
}
private boolean isFull(){
return (this.rear+1)%Length==this.front;
}
@Override
public int indexOf(Node node) throws Exception {
int i=0; //循环标志
boolean isMatch=false;
if (isEmpty())
throw new Exception("队列为空!");
while (head[i]!=null){
if (head[i]==node){
isMatch=true;
break;
}
i++;
}
if (!isMatch)
throw new Exception("该元素不存在");
return i;
}
@Override
public void add(Node node) throws Exception {
if (isFull())
throw new Exception("队列已满!");
head[this.rear]=node;
this.rear=(this.rear+1)%Length;
}
@Override
public Node pop() throws Exception {
if (isEmpty())
throw new Exception("当前队列为空!");
Node temp=head[this.front];
this.front=(this.front+1)%Length;
return temp;
}
}