数据结构学习记录(二)-----栈与队列(基于动态数组的实现)
栈(stack):只能在一端进行插入和删除操作操作的线性表。
其中,能够进行操作的一端称“栈顶(top)”,不能操作的一端称为“栈底(bottom)”。
也就是说插入与删除元素都要从栈顶开始。所有有了后进先出这一说。
注意点:
栈顶与栈底没有绝对的硬性要求,栈的顺序存储也是使用数组依次存储栈中数据元素,也就是说在数组的两端可以自己规定。
一般而言,大多数人还是喜欢把索引小的当做栈底。
最后要提醒的是,栈结构仅仅是一种思想,可以硬性的将规范化后的数组当做栈。
废话不多说,上代码!
目录结构:这里要说的是,这里实现的栈是基于数组底层实现的,没有直接调用jdk自带。
Array.java
public class Array<E> { private E[] data; private int size; // 构造函数,传入数组的容量capacity构造Array public Array(int capacity){ data = (E[])new Object[capacity]; size = 0; } // 无参数的构造函数,默认数组的容量capacity=10 public Array(){ this(10); } // 获取数组的容量 public int getCapacity(){ return data.length; } // 获取数组中的元素个数 public int getSize(){ return size; } // 返回数组是否为空 public boolean isEmpty(){ return size == 0; } // 在index索引的位置插入一个新元素e public void add(int index, E e){ if(index < 0 || index > size) throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size."); if(size == data.length) resize(2 * data.length); for(int i = size - 1; i >= index ; i --) data[i + 1] = data[i]; data[index] = e; size ++; } // 向所有元素后添加一个新元素 public void addLast(E e){ add(size, e); } // 在所有元素前添加一个新元素 public void addFirst(E e){ add(0, e); } // 获取index索引位置的元素 public E get(int index){ if(index < 0 || index >= size) throw new IllegalArgumentException("Get failed. Index is illegal."); return data[index]; } public E getLast(){ return get(size - 1); } public E getFirst(){ return get(0); } // 修改index索引位置的元素为e public void set(int index, E e){ if(index < 0 || index >= size) throw new IllegalArgumentException("Set failed. Index is illegal."); data[index] = e; } // 查找数组中是否有元素e public boolean contains(E e){ for(int i = 0 ; i < size ; i ++){ if(data[i].equals(e)) return true; } return false; } // 查找数组中元素e所在的索引,如果不存在元素e,则返回-1 public int find(E e){ for(int i = 0 ; i < size ; i ++){ if(data[i].equals(e)) return i; } return -1; } // 从数组中删除index位置的元素, 返回删除的元素 public E remove(int index){ if(index < 0 || index >= size) throw new IllegalArgumentException("Remove failed. Index is illegal."); E ret = data[index]; for(int i = index + 1 ; i < size ; i ++) data[i - 1] = data[i]; size --; data[size] = null; // loitering objects != memory leak if(size == data.length / 4 && data.length / 2 != 0) resize(data.length / 2); return ret; } // 从数组中删除第一个元素, 返回删除的元素 public E removeFirst(){ return remove(0); } // 从数组中删除最后一个元素, 返回删除的元素 public E removeLast(){ return remove(size - 1); } // 从数组中删除元素e public void removeElement(E e){ int index = find(e); if(index != -1) remove(index); } @Override public String toString(){ StringBuilder res = new StringBuilder(); res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length)); res.append('['); for(int i = 0 ; i < size ; i ++){ res.append(data[i]); if(i != size - 1) res.append(", "); } res.append(']'); return res.toString(); } // 将数组空间的容量变成newCapacity大小 private void resize(int newCapacity){ E[] newData = (E[])new Object[newCapacity]; for(int i = 0 ; i < size ; i ++) newData[i] = data[i]; data = newData; } }
ArrayStack.java
public class ArrayStack<E> implements Stack<E> { private Array<E> array; public ArrayStack(int capacity){ array = new Array<>(capacity); } public ArrayStack(){ array = new Array<>(); } @Override public int getSize(){ return array.getSize(); } @Override public boolean isEmpty(){ return array.isEmpty(); } public int getCapacity(){ return array.getCapacity(); } @Override public void push(E e){ array.addLast(e); } @Override public E pop(){ return array.removeLast(); } @Override public E peek(){ return array.getLast(); } @Override public String toString(){ StringBuilder res = new StringBuilder(); res.append("Stack: "); res.append('['); for(int i = 0 ; i < array.getSize() ; i ++){ res.append(array.get(i)); if(i != array.getSize() - 1) res.append(", "); } res.append("] top"); return res.toString(); } }
Stack.java
public interface Stack<E> { int getSize(); boolean isEmpty(); void push(E e); E pop(); E peek(); }
Main.java
public class Main { public static void main(String[] args) { ArrayStack<Integer> stack = new ArrayStack<>(); for(int i = 0 ; i < 5 ; i ++){ stack.push(i); System.out.println(stack); } stack.pop(); System.out.println(stack); } }
运行结果:
队列:限定只能在一端进行插入,而在另一端进行删除的线性表。
允许插入的一端叫队尾(rear),允许删除的一端称为对头(frond)。
一般选择下标小的为队首(frond),
队列也是基于数组的一种抽象数据类型。
进队列(插入)在队尾进行,出队列只在队头进行。
frond指示的位置=队头元素位置;
rear指示的位置=队尾元素所在位置的下一个元素。
当数据元素出队时,frond=frond+1,既frond后移一位,指向新的队头元素。 当元素进队时,rear=rear+1,既新元素放在rear,在将rear的索引后移一位!
下面看下实现代码p;
目录结构:
Array.java和上面的一样,这里就不粘贴复制啦!
ArrayQueeue.java
https://github.com/tiejiang-sunyubin/LooopQueue.git
由于代码太多,上传至github,以后有长代码都会上传至github。
这里有以下几点是最为重要的。
先是进队代码!进队时,会先判断是否为队满状态,如果队满,则扩充数组。
最后不要忘记维护数组的size。
public void enqueue(E e){ if((tail + 1) % data.length == front) resize(getCapacity() * 2); data[tail] = e; tail = (tail + 1) % data.length; size ++; }
接下来是给数组扩容代码!tail的索引正好是size的数值。
private void resize(int newCapacity){ E[] newData = (E[])new Object[newCapacity + 1]; for(int i = 0 ; i < size ; i ++) newData[i] = data[(i + front) % data.length]; data = newData; front = 0; tail = size; }
接下来是,出队代码!出队代码,设置十分巧妙,如果发现为数组的容量在1/4处到1/2处,则将数组的容量给缩小一半。
public E dequeue(){ if(isEmpty()) throw new IllegalArgumentException("Cannot dequeue from an empty queue."); E ret = data[front]; data[front] = null; front = (front + 1) % data.length; size --; if(size == getCapacity() / 4 && getCapacity() / 2 != 0) resize(getCapacity() / 2); return ret; }
下面是mian执行代码!这里的执行代码,完全展现了基于动态数组的队列。
public static void main(String[] args){ LoopQueue<Integer> queue = new LoopQueue<>(); for(int i = 0 ; i < 10 ; i ++){ queue.enqueue(i); System.out.println(queue); if(i % 3 == 2){ queue.dequeue(); System.out.println(queue); } } }
以下是运行结果,从运行结果中,可以看出入队和出队的威力。
- JavaScript学习总结(二十一)——使用JavaScript的数组实现数据结构中的队列与堆栈
- 数据结构 多线程安全队列基于数组实现
- 队列--基于动态循环数组实现(Java)
- 数据结构学习之——数组队列和循环队列的实现与效率的测试
- 数据结构学习记录连载10(队列提高要求实现)
- 数据结构学习---堆栈的动态数组实现及链表实现
- 数据结构学习---堆栈的动态数组实现及链表实现
- 数据结构之——基于数组实现的循环队列
- 数据结构学习记录连载10(队列提高要求实现)
- 基于动态数组的队列实现
- 数据结构队列之环形队列的动态数组实现:queue
- 一步一步学习java数组学习(ch5)数3退1记录最后留下来的在队列中的位置
- java 基于数组实现的队列
- 使用JavaScript的数组实现数据结构中的队列与堆栈
- 一步一步学习java数组学习(ch5)数3退1记录最后留下来的在队列中的位置
- JAVA学习笔记(十)基于LinkedList实现栈和队列
- [数据结构]C#基于数组实现泛型顺序表
- Oracle学习记录之使用自定义函数和触发器实现主键动态生成
- 数据结构学习记录连载9(队列的学习)
- 数据结构学习之循环队列c++实现