1.使用java中的数组
动态数组
public class Array<E> { private E[] data; private int size; public Array(int capacity) { data = (E[])new Object[capacity]; 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(""); } 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++; } E get(int index){ if(index<0||index>=size){ throw new IllegalArgumentException(""); } return data[index]; } void set (int index,E e){ if(index<0||index>=size){ throw new IllegalArgumentException(""); } 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; } public int find(E e){ for (int i=0;i<size;i++){ if(data[i].equals(e)){ return i; } } return -1; } //删除 public E remove(int index){ if(index<0||index>=size){ throw new IllegalArgumentException(""); } //将待删除元素存起来 用于返回 E ret =data[index]; //删除就是后面的直接覆盖 for (int i=index+1;i<size;i++){ data[i-1]=data[i]; } size--; data[size]=null;//自动回收 //动态减小数组 if(size==data.length/4&& data.length/2!=0){ resize(data.length/2); } return ret; } public E removeFist(){ return remove(0); } public E removeLast(){ return remove(size-1); } 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.("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(); } private void resize(int newCapacity){ E[] newData=(E[]) new Object[newCapacity]; for (int i=0;i<size;i++){ newData[i]=data[i]; } data=newData; } }
2.栈和栈的应用:撤销操作和系统栈
1.栈也是一种线性结构。
2.相比数组,栈对应的操作是数组的子集。
3.只能从一端添加元素,也只能从一端取出元素。
4.这一端称为栈顶。
A程序执行到A2这个位置去执行B程序,在B2这里执行c程序,c程序执行完成,去找应该执行的位置,就是B2.
package stack; import array.Array; public class ArrayStack<E> implements Stack<E> { //成员变量 Array<E> array; //构造函数 public ArrayStack(int capacity) { array = new Array<E>(capacity); } public ArrayStack() { array = new Array<E>(); } @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() { StringBuffer res=new StringBuffer(); 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 我们遍历字符,将左侧的括号以此压如栈中,开始遍历到右侧括号就和栈顶匹配,匹配成功就出栈,都遍历完了,栈是空的,当前这些括号是合法的。
反例:当遍历到右侧大括号时,与栈顶的中括号匹配失败了,
import java.util.Stack; public class Solution { public boolean isValid(String s) { Stack<Character> stack=new Stack<Character>(); 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; } char topChar=stack.pop(); if(c==')'&& topChar!='('){ return false; } if (c==']'&& topChar!='['){ return false; } if (c=='}'&& topChar!='{'){ return false; } } } return stack.isEmpty(); } }
3数组队列
队列也是一种线性结构
相比数组,队列对应的操作是数组的子集
只能从一端(队尾)添加元素,也只能从另一端(队首)取出元素。
package queue; import array.Array; public class ArrayQueue<E> implements Queue<E> { private Array<E> array; //构造函数 public ArrayQueue(int capacity){ array=new Array<E>(capacity); } public ArrayQueue(){ array=new Array<E>(); } @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.removeFist(); } @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(); } public static void main(String[] args) { ArrayQueue<Integer> queue=new ArrayQueue<Integer>(); for (int i=0;i<10;i++){ queue.enqueue(i); System..println(queue); if (i%3==2){ queue.dequeue(); System..println(queue); } } } }
4 循环队列
用数组实现对列,在出队时取走头部位置,后面的数据响应的需要往前移,所以时间复杂度是O(N)级别的,如果这些元素不移动位置,时间复杂度就会降到0(1)级别的。所以我们记录下队首和队尾的位置,就可以了。
循环对列需要两个指针,一个tail 每入队就++,取数据 front就++,为什么加循环对列:
当我们加到第7个元素时,tail+1对capacity取余 就是 0,前提是数组没有满,如果满了 就扩容。
package queue; public class LoopQueue<E> implements Queue<E> { private E[] data; private int front,tail; private int size; public LoopQueue(int capacity){ data=(E[])new Object[capacity+1]; front=0; tail=0; size=0; } public LoopQueue(){ this(10); } 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[] 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; } @Override public E dequeue() { //出队,先判断对列是否为空 if (isEmpty()){ throw new IllegalArgumentException("error"); } 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("error"); } return data[front]; } @Override public String toString() { StringBuilder res=new StringBuilder(); res.append(String.("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(); } }
5 什么是链表
package linkedList; public class LinedList<E> { //内部类 private class Node{ public E e; public Node next; //构造方法 public Node(E e,Node next){ this.e=e; this.next=next; } public Node(E e){ this(e,null); } //无参构造器 public Node(){ this(null,null); } @Override public String toString() { return e.toString(); } } }
带有尾针的链表:使用链表实现队列
package queue; public class LinkedListQueue<E> implements Queue<E> { private class Node { public E e; public Node next; //构造方法 public Node(E e, Node next) { this.e = e; this.next = next; } public Node(E e) { this(e, null); } //无参构造器 public Node() { this(null, null); } @Override public String toString() { return e.toString(); } } private Node head,tail; private int size; @Override public int getSize() { return size; } @Override public boolean isEmpty() { return size==0; } @Override public void enqueue(E e) { if(tail==null){ tail=new Node(e); head=tail; }else { tail.next=new Node(e); tail=tail.next; //头结点不要动 } size ++; } @Override public E dequeue() {//出队 if(isEmpty()){ throw new IllegalArgumentException("error"); } Node retNode=head;//出队元素的节点应该是头节点 head=head.next; retNode.next=null; if (head ==null){ tail=null; } size--; return retNode.e; } @Override public E getFront() { if(isEmpty()){ throw new IllegalArgumentException("error"); } return head.e; } @Override public String toString() { StringBuffer res=new StringBuffer(); res.append("Queue :front"); Node cur=head; while (cur!=null){ res.append(cur+"->"); cur=cur.next; } res.append("null tail"); return res.toString(); } public static void main(String[] args) { LinkedListQueue<Integer> queue=new LinkedListQueue<Integer>(); for (int i=0;i<10;i++){ queue.enqueue(i); System..println(queue); if (i%3==2){ queue.dequeue(); System..println(queue); } } } }
6 递归基础与递归的宏观语意
链表的天然递归结构性质
树结构
具体树结构 请看树结构浅析