数据结构一(数组,栈和队列)

数据结构

数据结构:研究的是数据如何在计算机中进行组织和存储,使得我们可以高效的获取数据和修改数据。

数据结构可以分为三类:

线性结构: 数组、队列、栈、链表、哈希表…

树型结构:二叉树、二分搜索树、AVL树,红黑树、堆、Trie、线段树、并查集…

图结构:邻接矩阵、邻接表

数据结构 + 算法 = 程序

数组

使用数组时,最重要的就是数组的索引,通过索引可以对数组进行增删改查操作。

在这里插入图片描述

数组最大的优点:快速查询。

数组最好应用于索引有语义的情况。

并非所有有语义的数字都可以作为数组的索引,例如:610521199610111188

数组也是可以处理“索引没有语义”的情况

创建数组并对数组进行操作

package com.company.lesson;
public class MyArray<T> {
    private T[] data;//数据容器
    private int size;//实际存放元素的个数

    public MyArray() {
        this(10);
    }
    public MyArray(int capacity) {
        data = (T[]) new Object[capacity];
        size = 0;
    }    
//获取数组中存放元素的个数
    public int getSize() {
        return size;
    }
//判断数组是否为空
    public boolean isEmpty() {
        return size == 0;
    }
//向数组末尾添加元素
    public void addTail(T ele) throws IllegalAccessException {
        add(ele,size);

    }
    //向数组中指定位置添加元素
    public void add(T ele,int index) throws IllegalAccessException {
        if(index<0||index>size){
            throw  new IllegalAccessException("index is error");
        }
        //判断数组是否已满,满了就进行扩容
        if(size == data.length){
            resize(2*data.length);
        }
        //元素后移
        for (int i = size-1; i >= index; i--) {
            data[i+1] = data[i];
        }
            data[index] = ele;
            size++;
    }
        //扩容
    private void resize(int newcapacity) {
        T[] newData = (T[]) new Object[newcapacity];
        for (int i = 0; i < size; i++) {
            newData[i] = data[i];
        }
        data = newData;
    }

    //向数组头部添加元素
    public void addHead(T ele) throws IllegalAccessException {
        add(ele,0);
    }
    //获取指定位置元素
    public T getEleByIndex(int index) throws IllegalAccessException {
        if(index<0||index>size-1){
            throw new IllegalAccessException("array is full");
        }
        return data[index];
    }
    //修改指定位置元素
    public void setEleByIndex(int index,T ele) throws IllegalAccessException {
        if(index<0||index>size-1){
            throw new IllegalAccessException("array is full");
        }
         data[index]=ele;
    }
    //获取头部元素
    public T getHead() throws IllegalAccessException {
        return getEleByIndex(0);
    }
    //获取尾部元素
    public T getTail() throws IllegalAccessException {
        return getEleByIndex(size-1);
    }
    //判断数组是否包含元素
    public boolean contains(T ele){
        boolean flag = false;
        for (int i = 0; i < size; i++) {
            if(data[i]==ele){
                flag = true;
                break;
            }
        }
        return flag;
    }
    //搜索指定元素的索引
    public int getIndex(T ele){
        int index = -1;
    //    Arrays.stream(data).filter(item->item == ele).findFirst();//filter()过滤
        for (int i = 0; i < size; i++) {
            if(data[i]==ele){
                index = i;
                break;
            }
        }
        return index;
    }
    //移除数组中指定位置元素
    public T removeEle(int index) throws IllegalAccessException {
        if(index<0||index>size-1){
            throw new IllegalAccessException("index is erreor");
        }
        T result = data[index];
        for (int i = index; i < size-1; i++) {
            data[i] = data[i+1];
        }
        size--;
        //缩容
        if(size <= data.length/4&&data.length/2!=0){
            resize(data.length/2);
        }
        return result;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("[");
        for (int i = 0; i <size ; i++) {
            sb.append(data[i]);
            if(i!=size-1){
                sb.append(",");//如果不是最后一个元素,就加,
            }
        }
        sb.append("],数组的容量为:");
        sb.append(data.length).append(",实际存放元素的个数:").append(size);
        return sb.toString();
    }
}

复杂度分析
在这里插入图片描述
resize的复杂度分析
9次addLast操作,出发resize,总共进行了17次基本操作,平均每次addLast操作,进行两次基本操作。
假设capacity = n,n+1次addLast,chufaresize,总共进行2n+1次基本操作
这样均摊计算:时间复杂度为O(1)
复杂度震荡
在这里插入图片描述

栈也是一种线数据结构,只能从栈顶添加或取出元素(后进先出LIFO(Last In First Out)

具体实现

public interface Stack<T> {
    /*
    基本操作
    @param<T>
     */
     int getSize();//获取元素数量
     boolean isEmpty();//判断是否为空
     void push(T ele);//压入栈
     T pop();//出栈
     T peek();//获得栈顶元素
}

实现该接口的类要重写接口中的方法以及toString()方法

public class MyStack<T> implements Stack<T> {
    private MyArray<T> data;//数据容器
    private int size;//栈中元素数量

    public MyStack() {//构造方法
        data = new MyArray<>();
        size = 0;
    }

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

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

    @Override
    public void push(T ele) {
        try {
            data.addTail(ele);
            size++;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public T pop() {
        T result = null;
        try {
            result = data.removeTail();
            size--;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public T peek() {
        try {
            return data.getTail();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        result.append("栈中总共有" + size + "个元素");
        result.append("栈底[");
        try {
                for (int i = 0; i < size; i++) {
                    result.append(data.getEleByIndex(i));
                    if (i != size - 1) {
                        result.append(",");
                    }
                }
                result.append("]栈顶");
                return result.toString();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                return null;
            }
        }
    }

复杂度分析

在这里插入图片描述

队列

队列也是一种线性数据结构

只能从一端(队尾)添加元素,从另一端(队首)取出元素

先进先出(FIFO First In First Out)

具体实现

public interface Queue<T> {
    int getSize();//获取元素数量
    boolean isEmpty();//判断是否为空
    void enqueue(T ele);//入队
        T dequeue();//出队
        T getFrunt();//查看队首元素
}

实现该接口的类要重写接口中的方法以及toString()方法

public class MyQueue<T> implements Queue<T> {
    private MyArray<T> data;
    private int size;

    public MyQueue() {
        data = new MyArray<>();
       size = 0;
    }


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

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

    @Override
    public void enqueue(T ele) {
        try {
            data.addTail(ele);
            size++;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


    }

    @Override
    public T dequeue() {
        T result = null;
        try {
            result = data.removeHead();
            size--;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public T getFrunt() {
        T result = null;
        try {
            result = data.getHead();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return result;
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        result.append("队列中有"+size+"个元素");
        result.append("队首[");
            try {for (int i = 0; i < size; i++) {
                result.append(data.getEleByIndex(i));
                if (i != size - 1) {
                    result.append(",");
                }
            }
            result.append("]队尾");
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        return result.toString();
    }
}

复杂度分析

dequeue()操作的时间复杂度为O(n),原因时在出队时,数组后面的元素都要进行前移

为了解决前移的问题,可以使用front记录队首位置,使用tail记录入队元素位置,这就是循环队列

1.front == tail 队列为空

在这里插入图片描述

在这里插入图片描述

3.front == tail 队列为空 (tail +1) % c == front 队列满
在这里插入图片描述

循环队列

public class LoopQueue<T> implements Queue<T> {
    private T[] data;//数据容量
    private int front,tail;//队首位置和待插入元素位置
    private int size;

    public LoopQueue() {
        this(10);
    }
    public LoopQueue(int capacity){
        data = (T[]) new Object[capacity+1];
        front = 0;
        tail = 0;
    }

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

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

    @Override
    public void enqueue(T ele) {//入队
        if((tail+1)%data.length == front){
            resize(2*data.length);
        }
        tail = size;
        data[tail] = ele;
        size++;
        tail = (tail+1)%data.length;
    }
    private void resize(int newCapacity){//扩容
        T[] newdata = (T[]) new Object[newCapacity+1];
        for (int i = 0; i < size; i++) {
            newdata[i] = data[(front+i)%data.length];
        }
        tail = size;
        front = 0;
        data = newdata;
    }

    @Override
    public T dequeue() {//出队
        if(front == tail){
            return null;
        }
       T result = data[front];
        size--;
        front = (front+1)%data.length;
        if(size == data.length / 4 && data.length / 2 > 0){//缩容
            resize(data.length/2);
        }
        return null;
    }

    @Override
    public T getFrunt() {
        if(front == tail){
            return data[front];
        }
        return null;
    }
    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        result.append("队列中有"+size+"个元素");
        result.append("队首[");
        int temp = front;
        while (front!=tail){
            result.append(data[front]+",");
            front = (front+1)%data.length;
        }
        front = temp;
            result.append("]队尾");
        return result.toString();
    }
}

循环队列与数组队列性能比较

 public static void compareQueue(Queue queue){
        long startTime = System.nanoTime();
        int num = 100000;
        Random random = new Random();
        for (int i = 0; i < num; i++) {
            queue.enqueue(random.nextInt(100));
        }
        while(!queue.isEmpty()){
            queue.dequeue();
        }
        long endTime = System.nanoTime();
        System.out.println((endTime-startTime)/1000000000.0);
    }

public static void main(String[] args)  {
    Queue myQueue = new MyQueue();
    compareQueue(myQueue);//3.3923022
    myQueue = new LoopQueue();
    compareQueue(myQueue);//0.0116124

}

循环队列效率更高

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值