1.动态数组
1)注意点
java不支持直接new出泛型数组,需要使用ojbect进行转型
public Array(int capacity) {
this.data = (E[]) new Object[capacity];
this.size = 0;
}
使用add和remove改变数组长度时
若每次改变一个数组长度会影响性能
若每次改变二倍长度的话,均摊复杂度为O(1)
public void add(int index,E e) {
if (index<0||index>size) {
throw new IllegalArgumentException("add failed.index<0 or 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 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 < data.length; i++) {
data[i-1] = data[i];
}
size--;
data[size] = null;
if (size==data.length/2 && data.length!=0) {
reSize(data.length/2);
}
return ret;
}
但是这样有复杂度震荡的问题
假设数组长度为10,数组元素个数为10
使用addLast增加元素,使数组长度扩容两倍变为20
再使用removeLast删除元素,使数组长度缩减两倍变为10
反复此操作非常耗时
此时,addLast和removeLast的时间复杂度都为O(n)
所以在removeLast时判断数组长度缩减为的1/4时再将数组长度缩减一半,使用这种Lazy方式解决
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 < data.length; i++) {
data[i-1] = data[i];
}
size--;
data[size] = null;
if (size==data.length/4 && data.length!=0) {
reSize(data.length/2);
}
return ret;
}
2)源码
public class Array<E> {
private E[] data;
private int size;
public Array(int capacity) {
this.data = (E[]) new Object[capacity];
this.size = 0;
}
public Array() {
this(10);
}
public int getSize() {
return size;
}
public int getCapacity() {
return data.length;
}
public boolean isEmpty() {
return size==0;
}
public void addLast(E e) {
add(size, e);
}
public void addFirst(E e) {
add(0,e);
}
public void add(int index,E e) {
if (index<0||index>size) {
throw new IllegalArgumentException("add failed.index<0 or 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 reSize(int newCapacity) {
E[] newData = (E[])new Object[newCapacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData;
}
@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();
}
public E get(int index) {
if (index<0||index>=size) {
throw new IllegalArgumentException("get failed.index is illegal");
}
return data[index];
}
public void set(int index, E e) {
if (index<0||index>=size) {
throw new IllegalArgumentException("set failed.index is illegal");
}
data[index] = e;
}
public boolean contains(int index,E e) {
for (int i = 0; i < data.length; i++) {
if (data[i].equals(e)) {
return true;
}
}
return false;
}
public int find(E e) {
for (int i = 0; i < data.length; i++) {
if (data[i].equals(e)) {
return i;
}
}
return -1;
}
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 < data.length; i++) {
data[i-1] = data[i];
}
size--;
data[size] = null;
if (size==data.length/4 && data.length!=0) {
reSize(data.length/2);
}
return ret;
}
public E removeFirst() {
return remove(0);
}
public E removeLast() {
return remove(size-1);
}
public void removeElement(E e) {
int index = find(e);
if (index!=-1) {
remove(index);
}
}
}
2.栈
1)注意点
栈的实现需要使用动态数组类
在动态数组类中再加入getLast和getFirst方法
public E getLast() {
return get(size-1);
}
public E getFirst() {
return get(0);
}
源码中的push和pop方法均摊复杂度均为O(1)
其他方法的时间复杂度为O(1)
2)源码
创建Stack接口
public interface Stack<E> {
int getSize();
boolean isEmpty();
void push(E e);
E pop();
E peak();
}
创建Stack接口实现类ArrayStack即栈
public class ArrayStack<E> implements Stack<E>{
Array<E> array;
public ArrayStack(int capacity) {
array = new Array<>(capacity);
}
public ArrayStack() {
array = new Array<>();
}
public int getCapcity() {
return array.getCapacity();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
@Override
public void push(E e) {
array.addLast(e);
}
@Override
public E pop() {
return array.removeLast();
}
@Override
public E peak() {
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();
}
}
3)应用
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public boolean isVaild(String s) {
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(' || c == '[' || c == '{') {
stack.push(c);
}else {
if (stack.isEmpty()) {
return false;
}
Character topChar = stack.pop();
if (c == ')' && topChar != '(' ) {
return false;
}
if (c == ']' && topChar != '[' ) {
return false;
}
if (c == '}' && topChar != '{' ) {
return false;
}
}
}
return stack.isEmpty();
}
3.队列
1)注意点
队列的实现需要使用动态数组类
同样,在动态数组类中再加入getLast和getFirst方法
public E getLast() {
return get(size-1);
}
public E getFirst() {
return get(0);
}
使用动态数组实现的普通队列:ArrayQueue中的dequeue出队方法,每次出队都需要前移数组中所有的元素,所以复杂度为O(n),使用动态数组实现循环队列:LoopQueue可以解决,LoopQueue中的dequeue出队方法,每次出队改变队首下标front,均摊复杂度为O(1)
俩种队列的enqueue入队方法均摊复杂度都为O(1)
2)源码
创建Queue接口
public interface Queue<E> {
int getSize();
boolean isEmpty();
void enqueue(E e);
E dequeue();
E getFront();
}
创建接口实现类ArrayQueue
public class ArrayQueue<E> implements Queue<E>{
private Array<E> array;
public ArrayQueue() {
array = new Array<>();
}
public ArrayQueue(int capacity) {
array = new Array<>(capacity);
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
public int getCapacity() {
return array.getCapacity();
}
@Override
public void enqueue(E e) {
array.addLast(e);
}
@Override
public E dequeue() {
return array.removeFirst();
}
@Override
public E getFront() {
return array.getFirst();
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Queue: ");
res.append("front [");
for (int i = 0; i < array.getSize(); i++) {
res.append(array.get(i));
if (i!=array.getSize()-1) {
res.append(", ");
}
}
res.append("] tail");
return res.toString();
}
}
创建接口实现类LoopQueue
public class LoopQueue<E> implements Queue<E> {
private E[] data;
private int front;
private int tail;
private int size;
public LoopQueue() {
this(10);
}
public LoopQueue(int capacity) {
data = (E[]) new Object[capacity + 1];
front = 0;
tail = 0;
size = 0;
}
public int getCapacity() {
return data.length - 1;
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return front == tail;
}
@Override
public void enqueue(E e) {
if ((tail+1)%data.length==front) {
resize(getCapacity()*2);
}
data[tail] = e;
tail = (tail+1)%data.length;
size++;
}
private void resize(int newCapacity) {
E[] newdate = (E[]) new Object[newCapacity+1];
for (int i = 0; i < size; i++) {
newdate[i] = data[(i+front)%data.length];
}
data = newdate;
front = 0;
tail = size;
}
@Override
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;
}
@Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("queue is empty");
}
return data[front];
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(String.format("queue: size = %d , capacity = %d\n", size,getCapacity()));
res.append("front [");
for (int i = front; i != tail; i = (i+1)%data.length) {
res.append(data[i]);
if ((i+1)%data.length != tail) {
res.append(", ");
}
}
res.append("] tail");
return res.toString();
}
}