数据结构 Java (一) 线性表

本文详细讲解了顺序表、链表、堆栈及队列的基本概念、操作方法与效率分析,对比了不同数据结构的特点,适合初学者入门学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、 顺序表

由数组组成,最简单的结构

操作

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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值