数据结构---线性表、栈、队列(动态数组)

数据结构---线性表:

线性表

由n个数据元素构成的有序序列,逻辑表示为:a0,a1,a2,a3,.....an-1,当n=0是线性表为空表。

线性表的存储结构(用数组表示线性表)

对线性表的操作

插入

在线性表尾插入:直接插入

在表中插入,将要插入位置的元素及其之后的元素都向后移一位,然后在要插入的位置插入新元素

删除

删除表尾的元素:直接删除

删除表中的元素:将要删除的元素删除,将删除元素之后的元素向前移一位。

ArrayList代码如下: 

接口提供方法

package 接口;

public interface List<E> extends Iterable<E> {
//    添加
    public void add(E element);
//    添加到对应角标
    public void add(int index,E element);
//    删除
    public void remove(E element);
//    删除对应角标处元素
    public E remove(int index);
//    获取对应角标处元素
    public E get(int index);
//    替换对应角标的元素
    public E set(int index,E element);
//    线性表长度
    public int size();
//    获取对应元素所在的角标
    public int indexof(E element);
//    判断元素是否在线性表中
    public boolean contains(E element);
//    判空
    public boolean isEmpty();
//    清空线性表
    public void clear();
}

接口方法的实现:

package 实现;

import 接口.List;

import java.util.Arrays;
import java.util.Iterator;

public class Arraylist<E> implements List<E> {
    //线性表默认容量
    private static int DEFAULT_CAPACITY =10;
    //线性表存储容器
    private E[] data;
    //线性表元素有效个数,末尾添加的角标
    private int size;
    //创建一个默认容量的线性表
    public Arraylist(){
        this(DEFAULT_CAPACITY);
    }
    //创建一个用户指定容量的线性表
    public Arraylist(int capacity){
        if (capacity<0){
            throw new IllegalArgumentException("capacity must >= 0");
        }
        data= (E[]) new Object[capacity];
        size = 0;
    }
    //将数组转化为线性表
    public Arraylist(E[] arr){
        if (arr==null){
            throw new IllegalArgumentException("arr is null");
        }
        data = (E[]) new Object[arr.length];
        for (int i = 0;i < arr.length;i++){
            data[i]=arr[i];
        }
        size=arr.length;
    }
    @Override
    public void add(E element) {
        this.add(size,element);
    }
//指定角标
    @Override
    public void add(int index, E element) {
        if (index < 0||index > size){
            throw new IndexOutOfBoundsException("index out of bounds");
        }
        //判断线性表是否需要扩容
        if(size== data.length){
            resize(data.length*2);
        }
        for(int i = size-1; i >= index ; i--) {
            data[i+1]=data[i];
        }
        data[index]=element;
        size++;
    }
    //扩容 缩容
    private void resize(int newLength) {
        //创建一个新数组
        E[] newdata = (E[]) new Object[newLength];
        //将原数组元素放入
        for (int i = 0; i < size; i++) {
            newdata[i]=data[i];
        }
        data=newdata;
    }
    @Override
    public void remove(E element) {
        //获取角标
        int index=indexof(element);
        //若存在删除
        if (index!=-1) {
            remove(index);
        }
    }
    //删除指定角标处的元素 角标范围0-(size-1)
    @Override
    public E remove(int index) {
        if(index<0||index>= size){
            throw new IndexOutOfBoundsException("index out of bounds");
        }
        E ret = data[index];
        for(int i = index+1;i<size;i++){
            data[i-1]=data[i];
        }
        size--;
        //判断是否需要缩容 最小容量为DEFAULT_CAPACITY
        if(size == data.length/4 && data.length>DEFAULT_CAPACITY){
            resize(data.length/2);
        }
        return ret;
    }

    @Override
    public E get(int index) {
        if(index<0||index>= size){
            throw new IndexOutOfBoundsException("index out of bounds");
        }
        return data[index];
    }

    @Override
    public E set(int index, E element) {
        if(index<0||index>= size){
            throw new IndexOutOfBoundsException("index out of bounds");
        }
        E ret = data[index];
        data[index]=element;
        return ret;
    }

    @Override
    public int size() {
        return size;
    }
    //获取元素角标
    @Override
    public int indexof(E element) {
        for (int i = 0; i < size; i++) {
            if (element.equals(data[i])){
                return i;
            }
        }
        return -1;
    }

    @Override
    public boolean contains(E element) {
        return indexof(element)!=-1 ;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public void clear() {
        data= (E[]) new Object[DEFAULT_CAPACITY];
        size=0;
    }

    @Override
    public Iterator<E> iterator() {
        return new ArrayListIterator();
    }
    class ArrayListIterator implements Iterator<E>{
        private int cur = 0;
        //判断之后还有元素
        @Override
        public boolean hasNext() {
            return cur<size;
        }
        //后移并返回元素
        @Override
        public E next() {
            return data[cur++];
        }
    }

    @Override
    public String toString() {
       StringBuilder sb = new StringBuilder(String.format("ArrayList:%d/%d[",size,data.length));
       if (isEmpty()){
           sb.append(']');
       }else{
           for (int i = 0; i < size; i++) {
               sb.append(data[i]);
               if (i!=size-1){
                   sb.append(',');
               }else {
                   sb.append(']');
               }
           }
       }
       return sb.toString();
    }
}

测试:

package 测试;

import 实现.Arraylist;


public class ArrayListTest {
    public static void main(String[] args) {
        Arraylist<Integer> list = new Arraylist<>();
        System.out.println(list);
        for (int i = 1; i < 12; i++) {
            list.add(i);
        }
        System.out.println(list);
    }
}

结果展示 :

栈(基于上面的线性表实现,调用线性表中的方法)

定义;栈是一种用于存储数据的简单数据结构,有点类似链表或者顺序表(统称线性表),栈与线性表的最大区别是数据的存取的操作,我们可以这样认为栈(Stack)是一种特殊的线性表,其插入和删除操作只允许在线性表的一端进行。

入栈:先插入的元素靠近栈底,后插入的元素靠近栈顶

出栈:将靠近栈顶的元素依次出栈。

代码实现

接口定义方法:

package 接口;

public interface Stack<E> extends Iterable<E>{
    //元素个数
    public int size();
    //判空
    public boolean isEmpty();
    //压栈
    public void push(E element);
    //弹栈
    public E pop();
    //获取栈顶元素
    public E peek();
    //清空栈
    public void clear();
}

实现接口:

package 实现;

import 接口.Stack;

import java.util.Iterator;
//借用ArrayList(自己写的)
public class ArrayStack<E> implements Stack<E> {
    //栈内部由线性表实现
    private Arraylist<E> list;
    //创建就一个默认容量的栈
    public ArrayStack(){
        list = new Arraylist<>();
    }

    //创建一个指定容量的栈
    public ArrayStack(int capaticy){
        list = new Arraylist<>(capaticy);
    }
    //获取栈的元素个数
    @Override
    public int size() {
        return list.size();
    }
    //判空
    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }
    //入栈(线性表表尾添加元素)
    @Override
    public void push(E element) {
        list.add(element);
    }
    //弹栈一个元素(在线性表表尾删除元素)
    @Override
    public E pop() {
        return list.remove(list.size()-1);
    }
    //查看栈顶元素
    @Override
    public E peek() {
        return list.get(list.size()-1);
    }
    //清空栈(线性表)
    @Override
    public void clear() {
        list.clear();
    }
    //迭代
    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }
    //重写toString
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(String.format("ArrayStack:%d/%d[",size(),list.getCapacity()));
        if (isEmpty()){
            sb.append(']');
        }else{
            for (int i = 0; i < size(); i++) {
                sb.append(list.get(i));
                if (i!=size()-1){
                    sb.append(',');
                }else {
                    sb.append(']');
                }
            }
        }
        return sb.toString();
    }
}

测试:

package 测试;

import 实现.ArrayStack;

public class StackTest {
    public static void main(String[] args) {
        ArrayStack<Integer> stack = new ArrayStack<>();
        System.out.println(stack);
        for (int i = 1; i < 12; i++) {
            stack.push(i);
        }
        System.out.println(stack);
    }
}

结果展示:

双端栈

定义:一种特殊的栈,在两端都可进行增删操作。

代码实现

 

package 实现;

import java.util.Arrays;

public class ArrayDoubleStack<E> {
    //定义容器
    private E[] data;
    //左端栈顶ltop==-1
    private int ltop;
    //右端栈顶rtop==-1
    private int rtop;
    //默认容量
    private static int DEFAULT_SIZE=10;
    public ArrayDoubleStack(){
        data = (E[]) new Object[DEFAULT_SIZE];
        ltop=-1;
        rtop=data.length;
    }
    //入栈
    public void push(E element , int stackId){
        if (ltop+1==rtop){
            resize(data.length*2);
        }
        switch (stackId){
            case 0://左端入栈
                data[++ltop] = element;
                break;
            case 1://右端入栈
                data[--rtop]=element;
                break;
        }
    }
    //出栈
    public E pop(int stackId){
        if (isEmpty(stackId)){
            throw new NullPointerException("stack is null");
        }
        E ret = null;
        switch (stackId){
            case 0:
                ret=data[ltop--];
                break;
            case 1:
                ret=data[rtop++];
                break;
        }
        //缩容
        if (size(0)+size(1)==data.length/4&&data.length>DEFAULT_SIZE){
            resize(data.length/2);
        }
        return ret;
    }
    //改变容量
    private void resize(int newLength) {
        E[] newdata = (E[]) new Object[newLength];
        //左端入栈
        for (int i = 0; i <= ltop; i++) {
            newdata[i]=data[i];
        }
        //右端入栈
        int index = rtop;
        for (int i = newLength-size(1); i <newLength ; i++) {
            newdata[i]=data[index++];
        }
        rtop = newLength-size(1);
        data = newdata;
    }

    public int size(int stackId){
        switch (stackId){
            case 0 :
                return ltop+1;
            case 1:
                return data.length-rtop;
        }
        return -1;
    }
    //判空
    private boolean isEmpty(int stackId) {
        switch (stackId){
            case 0:
                return ltop==-1;
            case 1 :
                return rtop== data.length;
        }
        return false;
    }
    public E peek(int stackId){
        if (isEmpty(stackId)){
            throw new NullPointerException("stack is null");
        }
        switch (stackId) {
            case 0:
                return data[ltop];
            case 1:
                return data[rtop];
        }
        return null;
    }
    public void clear(int stackId){
        switch (stackId){
            case 0:
                ltop=-1;
                break;
            case 1:
                rtop=data.length;
                break;
        }
    }

    @Override
    public String toString() {
       StringBuilder sb = new StringBuilder(String.format("ArrayDoubleStack:%d/%d\n",size(0)+size(1),data.length));
       if (isEmpty(0)){
           sb.append("leftStack:[]");
       }else{
           sb.append("leftStack:[");
           for (int i = 0; i <= ltop; i++) {
               sb.append(data[i]);
               if (i==ltop){
                   sb.append(']');
                   sb.append('\n');
               }else{
                   sb.append(',');
               }
           }
       }
        if (isEmpty(1)){
            sb.append("rightStack:[]");
        }else{
            sb.append("rightStack:[");
            for (int i = data.length-1; i >= rtop; i--) {
                sb.append(data[i]);
                if (i==rtop){
                    sb.append(']');
                    sb.append('\n');
                }else{
                    sb.append(',');
                }
            }
        }
        return sb.toString();
    }
}

测试

package 测试;

import 实现.ArrayDoubleStack;

public class ArrayDoubleStackTest {
    public static void main(String[] args) {
        ArrayDoubleStack<Integer> stack = new ArrayDoubleStack<>();
        System.out.println(stack);
        for (int i = 1; i <= 6; i++) {
            stack.push(i,0);
        }
        System.out.println(stack);
        for (int i = 7; i <= 12; i++) {
            stack.push(i,1);
        }
        System.out.println(stack);
    }
}

结果展示

队列

定义:只允许在一端进行插入操作,而在另一端进行删除操作的线性表。队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头

代码实现

接口定义方法

package 接口;

public interface Queue<E> extends Iterable<E> {
    //队列长度
    public int size();
    //判空
    public boolean isEmpty();
    //入队
    public void offer(E element);
    //出队
    public E pop(E element);
    //获取队顶元素
    public E element();
    //清空
    public void clear();
}

实现接口方法

package 实现;

import 接口.Queue;

import java.util.Iterator;

public class ArrayQueue<E> implements Queue<E> {
   private Arraylist list;
   public ArrayQueue(){
        this(10);
   }
   public ArrayQueue(int capacity){
       list= new Arraylist<>(capacity);
   }
   //有效元素个数
    @Override
    public int size() {
        return list.size();
    }
    //判空
    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }
    //入队
    @Override
    public void offer(E element) {
        list.add(element);
    }
    //出队
    @Override
    public E pop(E element) {
        return (E) list.remove(0);
    }
    //获取队首元素
    @Override
    public E element() {
        return (E) list.get(0);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(String.format("ArrayQueen:%d/%d[",size(),list.getCapacity()));
        if(isEmpty()){
            sb.append(']');
        }else{
            for (int i = 0; i < size(); i++) {
                sb.append(list.get(i));
                if (i!=size()-1){
                    sb.append(',');
                }else{
                    sb.append(']');
                }
            }
        }
        return sb.toString();
    }

    //清空
    @Override
    public void clear() {
        list.clear();
    }
    //迭代
    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }
}

测试

package 测试;

import 实现.ArrayQueue;

public class ArrayQueueTest {
    public static void main(String[] args) {
        ArrayQueue<Integer> queen = new ArrayQueue<>();
        System.out.println(queen);
        for (int i = 1; i <=12 ; i++) {
            queen.offer(i);
        }
        System.out.println(queen);
    }
}

结果展示

队列---循环队列

定义:为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列

初始队列形状:定义两个指针

对队列进行插入操作:

当rear指向最后一个位置时,再添加元素:

    初始:

     插入后:

注:

  • 判空:判断空间是否没有元素,front==rear且size=0;
  • 判满:判断空间中的元素是否已满,(rear+1)%空间的长度
  • 实际存储最大元素空间是空间的长度-1;

代码实现

实现

package 实现;


import 接口.Queen;

import java.util.Iterator;

public class ArrayLoopQueue<E> implements Queen<E> {
    //容器
    private E[] data;
    //队首指针 front
    private int front;
    //队尾指针 rear 对空:rear==front 对满:(rear+1)%n=front
    private int rear;
    //有效元素个数
    private int size;
    //定义默认容量10,实际容量为9
    private static int DEFAULT_SIZE=10;
    public ArrayLoopQueue(){
        this(DEFAULT_SIZE);
    }
    public ArrayLoopQueue(int capacity){
        data= (E[]) new Object[capacity+1];
        front=0;
        rear=0;
        size=0;
    }
    //长度
    @Override
    public int size() {
        return size;
    }
    //判空
    @Override
    public boolean isEmpty() {
        return size==0&&front==rear;
    }
    //添加
    @Override
    public void offer(E element) {
        //扩容
        if((rear+1)% data.length==front){
            resize(data.length * 2 - 1);
        }
        data[rear]=element;
        rear=(rear + 1)%data.length;
        size++;
    }
    //出队
    @Override
    public E pop(E element) {
        if(isEmpty()){
            throw new NullPointerException("queen is null");
        }
        E ret = data[front];
        front=(front+1)% data.length;
        size--;
        //缩容
        if (size== (data.length-1)/4&&data.length-1>DEFAULT_SIZE){
            resize(data.length/2+1);
        }
        return ret;
    }

    private void resize(int newLength) {
        E[] newData= (E[]) new Object[newLength];
        int index = 0;
        for (int i = front; i!=rear; i=(i+1)% data.length) {
            newData[index++] = data[i];
        }
        front=0;
        rear=index;
        data=newData;
    }

    @Override
    public E element() {
       if (isEmpty()){
           throw new NullPointerException("data is null");
       }
       return data[front];
    }

    @Override
    public void clear() {
        data= (E[]) new Object[DEFAULT_SIZE+1];
        front=0;
        rear=0;
        size=0;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(String.format("ArrayLoopQueen:[ %d/%d ", size, data.length - 1));
        if (isEmpty()) {
            sb.append(']');
        } else {
            for (int i = front; i != rear; i = (i + 1) % data.length) {
                sb.append(data[i]);
                if ((i + 1) % data.length == rear) {
                    sb.append(']');
                } else {
                    sb.append(',');
                }
            }
        }
        return sb.toString();
    }
    @Override
    public Iterator<E> iterator() {
        return null;
    }
    class ArrayLoopQueenTterator implements Iterator<E>{
        private int cur;
        @Override
        public boolean hasNext() {
            return cur != rear;
        }

        @Override
        public E next() {
            E ret = data[cur];
            cur = (cur+1)%data.length;
            return ret;
        }
    }
}

测试

package 测试;

import 实现.ArrayLoopQueue;

public class ArrayLoopQueueTest {
    public static void main(String[] args) {
        ArrayLoopQueue<Integer> queen = new ArrayLoopQueue<Integer>();
        System.out.println(queen);
        for (int i = 1; i <= 12; i++) {
            queen.offer(i);
        }
        System.out.println(queen);
    }

}

结果展示

队列---双端队列

定义:其两端都可以入列和出列的数据结构,队列后面(rear)可以加入和移出数据,队列前面(front)可以加入和移出数据

代码实现:

接口定义方法

package 接口;

public interface Dqueue<E> extends Queen<E> {
    //队首添加元素
    public void addfirst(E element);
    //队尾添加元素
    public void addlast(E element);
    //队首删除元素
    public E removefirst();
    //队尾删除元素
    public E removelast();
    //获取队首元素
    public E getfirst();
    //获取队尾元素
    public E getlast();
    //获取有效元素个数
    public int size();
    //判空
    public boolean isEmpty();
    //清空
    public void clear();
}

实现接口方法

package 实现;

import 接口.Dqueue;
import 接口.Stack;

import java.util.Iterator;

public class ArrayDqueue<E> implements Dqueue<E>, Stack<E> {
    //容器
    private E[] data;
    //左指针
    private int front;
    //右指针
    private int rear;
    //有效长度
    private int size;
    //默认容量
    private static int DEFAUL_SIZE=10;
    public ArrayDqueue(){
        this(DEFAUL_SIZE);
    }
    public ArrayDqueue(int capacity){
        data= (E[]) new Object[capacity+1];
        front=0;
        rear=0;
        size=0;
    }
    //队首添加
    @Override
    public void addfirst(E element) {
        if (isFull()){
            resize(data.length*2-1);
        }
        front=(front-1+ data.length)% data.length;
        data[front]=element;
        size++;
    }
    //扩容
    private void resize(int newLength) {
        E[] newData= (E[]) new Object[newLength];
        int index = 0;
        for (int i = front; i!=rear; i=(i+1)% data.length) {
            newData[index++] = data[i];
        }
        front=0;
        rear=index;
        data=newData;
    }
    //判满
    private boolean isFull() {
        return (rear+1)% data.length==front;
    }
    //队尾添加
    @Override
    public void addlast(E element) {
        //判断是否需要扩容
        if (isFull()){
            resize(data.length*2-1);
        }
        data[rear]=element;
        rear=(rear+1)% data.length;
        size++;
    }
    //队首删除
    @Override
    public E removefirst() {
        //判空
        if (isEmpty()){
            throw new NullPointerException("queen is null");
        }
        E ret = data[front];
        front=(front+1)% data.length;
        size--;
        //判断是否要缩容
        if(isSmall()){
            resize(data.length/2+1);
        }
        return ret;
    }

    private boolean isSmall() {
        return size== (data.length-1)/4 && data.length-1>DEFAUL_SIZE;
    }
    //队尾删除
    @Override
    public E removelast() {
        //判空
        if (isEmpty()){
            throw new NullPointerException("queen is null");
        }
        E ret = data[(rear-1+ data.length)% data.length];
        rear=(rear-1+ data.length)% data.length;
        size--;
        return ret;
    }
    //获取队首元素
    @Override
    public E getfirst() {
        return data[front];
    }

    @Override
    public E getlast() {
        return data[(rear-1+ data.length)% data.length];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0 && front==rear;
    }
    //入栈 front 栈底 rear 栈顶
    @Override
    public void push(E element) {
        addlast(element);
    }

    @Override
    public E pop() {
        return removelast();
    }

    @Override
    public E peek() {
        return getlast();
    }
    //front 队首  rear 队尾
    @Override
    public void offer(E element) {
        addlast(element);
    }

    @Override
    public E pop(E element) {
        return removefirst();
    }

    @Override
    public E element() {
        return getfirst();
    }

    @Override
    public void clear() {
        data= (E[]) new Object[DEFAUL_SIZE+1];
        front=0;
        rear=0;
        size=0;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(String.format("ArrayDqueen:[ %d/%d ", size, data.length - 1));
        if (isEmpty()) {
            sb.append(']');
        } else {
            for (int i = front; i != rear; i = (i + 1) % data.length) {
                sb.append(data[i]);
                if ((i + 1) % data.length == rear) {
                    sb.append(']');
                } else {
                    sb.append(',');
                }
            }
        }
        return sb.toString();
    }

    @Override
    public Iterator<E> iterator() {
        return null;
    }
    //迭代放向 front->rear
    class ArrayLoopQueenTterator implements Iterator<E>{
        private int cur;
        @Override
        public boolean hasNext() {
            return cur != rear;
        }

        @Override
        public E next() {
            E ret = data[cur];
            cur = (cur+1)%data.length;
            return ret;
        }
    }
}

测试:

package 测试;

import 实现.ArrayDqueue;

public class ArrayDqueueTest {
    public static void main(String[] args) {
        ArrayDqueue<Integer> dqueen = new ArrayDqueue<Integer>();
        System.out.println(dqueen);
        dqueen.addlast(1);
        dqueen.addfirst(2);
        System.out.println(dqueen);
    }
}

结果展示

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值