一、 顺序表
由数组组成,最简单的结构
操作
1. 插入
pubilc void insert(int i,Object obj) throws Exception{
if(size == maxSize){
throw new Exception("已满");
}
if(i<0 || i>size){
throw new Exception("参数错");
}
for(int j=size;j>i;j--) //指定位置之后的数据向后移一位
listArray[j] = listArray[j-1];
listArray[i] = obj ;
size++;
2. 删除
public Object delete(int i) throws Exception{
if(size=0){
throw new Exception("已空");
}
if(i<0 || i>size-1{
throw new Exception("参数错");
}
Object it=listArray[i];
for(int j=i;j<size-1;j++)//删除位置之后的数据向前移一位
listArray[j] = listArray[j+1];
size--;
return it;
}
效率分析
- 删除/插入一个数据元素成员的时间复杂度:O(n)
- 最好情况:插入/删除最后一个元素
- 最坏情况:插入/删除第一个元素
- 优点:取数据效率高,内存空间利用率高
- 缺点:插入删除时要移动的元素多
二、 链表
可分为带头结点链表&不带头结点链表(带头结点实现简单,下列代码都是带头结点的情况)
(1)单链表
结点组成:一个数据元素+一个指针
用对象引用表示指针,指向下一个结点
操作
1. 查找元素
public void index(int i) throws Exception{
if(i<-1 || i>size-1){
throw new Exception("参数错误");
}
if(i==-1) return;
current = head.next;
int j=0;
while((current!=null)&&j<i){ //从头一个一个查询
current=current.next;
j++;
}
}
2. 插入
public void insert(int i,Object obj) throws Exception{
if(i<0 || i>size){
throw new Exception("参数错误!");
}
index(i - 1); //先定位再重新连指针
current.setNext(new Node(obj,current.next));
size++;
}
3. 删除
public Object delete(int i) throws Exception{
if(size == 0){
throw new Exception("链表已空无元素可删除!");
}
if(i<0 || i>size-1){
throw new Exception("参数错误!");
}
index(i-1);
Object obj = current.next.getElement();//记录要删除的元素,return时用到
current.setNext(current.next.next);//跳开要删除的元素,重新链接指针
size --;
return obj;
}
效率分析
- 插入/删除/取元素的时间复杂度:O(n)
- 优点:插入/删除时不用移动元素
- 缺点:每个结点都有指针,空间利用率低,不支持随机读取,每次读取都要从头开始查找
(2)循环单链表
最后一个结点指向第一个结点
(3)双向链表
结点组成:一个前驱指针+一个数据元素+一个后继指针
(4)仿真链表
在数组中增加int型变量域作为仿真指针,记录下一个元素的下标(有点类似结构体)
三、 堆栈
只允许在栈顶插入和删除(后进先出)
有顺序堆栈&链式堆栈
操作
1. 入栈
顺序堆栈(数组实现)
public void push(Object obj) throws Exception{
if(top==maxStackSize){
throw new Exception("堆栈已满");
}
stack[top] = obj;
top++;
}
链式堆栈(链表实现)
public void push(Object obj){
head = new Node(obj,head); //为元素obj创建一个新的结点,并使head指针指向它
size++;
}
2. 出栈
顺序堆栈(数组实现)
public Object pop() throws Exception{
if(top == 0){
throw new Exception("堆栈已空!");
}
top -- ;//只修改栈顶指针top
return stack[top];
}
链式堆栈(链表实现)
public Object pop() throws Exception{
if(size==0){
throw new Exception("堆栈已空!");
}
Object obj= head.data; //获取栈顶元素,作为return值
head=head.next;//修改栈顶指针
size--;
return obj;
}
3. 取栈顶
顺序堆栈(数组实现)
public Object getTop() throws Exception{
if(top==0){
throw new Exception("堆栈已空");
}
return stack[top - 1];
}
链式堆栈(链表实现)
public Object getTop(){
return head.data;
}
四、 队列
队尾入,队头出(先进先出)【类似食堂排队买饭!】
有顺序队列&链式队列
顺序循环队列要点
1. 顺序队列的假溢出问题【即为什么要用顺序循环队列】
元素入队列后,位置不会移动【即下标不会改变】,当有元素出队列时,会空出该位置,如果此时队尾的位置有元素占用【即下标=maxSize的位置有元素】,下一个元素不能从队尾进入,但实际上队列中有空的位置
例:
一个顺序队列最大存储空间maxSize=3,元素有SeqQueue[0]=A,SeqQueue[1]=B,SeqQueue[2]=C,当A出队列后,空出0号位,如果此时存入D元素,会因为2号位有元素,错误的认为队列已满,但实际上0号为空闲
2. 基本原理
把顺序队列的存储空间构造成一个逻辑上
首尾相连的循环队列,每次有元素入队列和出队列时,改变队头指针和队尾指针,则能解决假溢出问题。
3. 判别队空和队满
队空和队满时,front==rear都成立,因此要用其他条件区分。
三种方法:
- 少用一个存储空间,用rear+1==front判断队满,rear==front判断队空
- 设一个标志位,初始tag=0,当入队操作成功时tag=1,用tag=1&&rear=front判断队满,tag=0&&rear=front判断队空
- 设置一个计数器count,记录队列中元素个数【此方法最好,不仅具备计数作用,还能标志队空】
操作
1. 入队列
顺序循环队列(数组实现)
public void append(Object obj) throws Exception{
if(count>0 && front == rear){ //如果是不循环的顺序队列,则要考虑count是否等于maxSize
throw new Exception("队列已满");
}
data[rear]=obj;
rear=(rear+1)%maxSize; //如果是不循环的顺序队列,则rear=rear+1
count++;
}
链式队列(链表实现)
public void append(Object obj){
Node newNode = new Node(obj,null);
if(rear!=null)
rear.next = newNode;
rear=newNode;//如果队尾不为空,则插入队尾
if(front==null)//如果队头为空,则把该结点设置为头结点
front=newNode;
count++;
}
2. 出队列
顺序循环队列(数组实现)
public Object delete() throws Exception{
if(count==0)
throw new Exception("队列已空");
}
Object temp=data[front];
front = (front+1)%maxSize;//如果是不循环的顺序队列,则front=front+1;
count--;
return temp;
}
链式队列(链表实现)
public Object delete() throws Exception{
if(count==0)
throw new Exception("队列已空");
}
Node temp=front;
front = front.next;
count--;
return temp.getElement();
}
3. 取队头
顺序循环队列(数组实现)
public Object getFront() throws Exception{
if(count==0)
throw new Exception("队列已空");
}
return data[front];
}
链式队列(链表实现)
public Object getFront() throws Exception{
if(count==0)
throw new Exception("队列已空");
}
return front.getElement();
}