算法第一章
使我们可以高效获取数据和修改数据
分为 线性结构,树结构,图结构
数据库中包含大量数据结构,系统任务切换,文件切换,寻路算法。
线性结构
数组,栈,队列,链表,哈希表
其中,动态数组,栈,队列,底层依托静态数组,靠resize解决固定容量问题
树结构
二叉树,二分搜索树,红黑树
图结构
邻接矩阵,邻接表
算法第二章
新建一个数组
private E[] data;
//data有多少有效容量
private int size;
/**
* 构造函数,传入数组的容量capacity构造Array
* @param capacity
*/
public Array(int capacity){
data= (E[])new Object[capacity];
size=0;
}
/**
* 无参构造函数,默认数组的容量capacity=10
*/
public Array(){
this(10);
}
public Array(E[] arr){
data= (E[]) new Object[arr.length];
for (int i=0;i<arr.length;i++){
data[i] = arr[i];
}
size=arr.length;
}
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);
}
//在第index个位置插入新元素e
public void add(int index,E e){
if(index<0||index>size){
throw new IllegalArgumentException("Require index in 0 to 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 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(E e){
for (int i=0;i<size;i++){
if(data[i].equals(e)){
return true;
}
}
return false;
}
//查找数组中元素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);
}
public void removeElement(E e){
int index=find(e);
if(index!=-1){
remove(index);
}
}
private void resize(int newCapacity) {
E[] newData= (E[]) new Object[newCapacity];
for(int i=0;i<size;i++){
newData[i]=data[i];
}
data=newData;
}
public E getLast(){
return get(size-1);
}
public E getFirst(){
return get(0);
}
@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 void swap(int i,int j){
if(i < 0 || i >= size || j <0 || j>=size){
throw new IllegalArgumentException("index is illegal.");
}
E t = data[i];
data[i] = data[j];
data[j] = t;
}
算法复杂度-时间复杂度
O(1),O(n),O(nlogn),O(n^2)
大O描述的是算法的运行时间和输入数据之间的关系
n是nums中的元素个数 算法和n呈线性关系
栈 Stack
栈也是一种线性结构
栈是一种后进先出的数据结构
相比数组,栈对应的操作是数组的子集
栈只能从一端添加元素,也只能从一端取出元素
这一端称为栈顶
一个简单的数组栈:
public class ArrayStack<E> implements Stack<E> {
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();
}
栈的应用
undo操作(撤销)
程序调用的系统栈(方法找到上次中断的位置)
使用栈解决括号匹配的问题
public boolean isValid(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;
char topChar = stack.pop();
if(c == ')' && topChar != '(')
return false;
if(c == ']' && topChar != '[')
return false;
if(c == '}' && topChar != '{')
return false;
}
}
return stack.isEmpty();
}
队列 Queue
队列是一种先进先出的数据结构
一个简单的数组队列
public class ArrayQueue<E> implements Queue<E> {
private Array<E> array;
public ArrayQueue(int capacity){
array=new Array<>(capacity);
}
public ArrayQueue(){
array=new Array<>();
}
@Override
public void enqueue(E e) {
array.addLast(e);
}
/**
*出队时间复杂度是O(n)级别
* @return
*/
@Override
public E dequeue() {
return array.removeFirst();
}
@Override
public E getFront() {
return array.getFirst();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
public int getCapacity(){
return array.getCapacity();
}
@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 class LoopQueue2<E> implements Queue<E> {
private E[] data;
private int front,tail;
//private int size; size代表当前队列中元素个数 tail-front
public int getSize(){
if(tail>front){
return (tail-front)+1;
}else if(tail<front){
return tail+getCapacity()-front;
}else{
return 0;
}
}
public LoopQueue2(int capacity){
data=(E[])new Object[capacity+1];
front=0;
tail=0;
}
public LoopQueue2(){
this(10);
}
public int getCapacity(){
return data.length-1;
}
@Override
public void enqueue(E e) {
if((tail+1)%data.length==front){
resize(getCapacity()*2);
}
data[tail]=e;
tail=(tail+1)%data.length;
}
private void resize(int newCapacity) {
E[] newData= (E[]) new Object[newCapacity+1];
for (int i=0;i<getSize();i++){
newData[i]=data[(i+front)%data.length];
}
data=newData;
front=0;
tail=getSize();
}
@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;
if(getSize()==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 int getSize() {
return size;
}*/
@Override
public boolean isEmpty() {
return front==tail;
}
@Override
public String toString(){
StringBuilder res=new StringBuilder();
res.append(String.format("Queue:size=%d,capacity=%d\n",getSize(),getCapacity()));
//res.append("Queue: ");
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();
}
}
链表 Linked List
真正的动态数据结构。
最简单的动态数据结构。
更深入的理解引用(或者指针)
更深入的理解递归
所在内存地址随机
链表:
public class LinkedList<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 dummyHead;
int size;
public LinkedList(){
dummyHead=new Node(null,null);
size=0;
}
public int getSize(){
return size;
}
public boolean isEmpty(){
return size==0;
}
//在链表头添加新的元素e
public void addFirst(E e){
add(0,e);
}
//在链表的index(0-based)位置添加新的元素e
//在链表中不是一个常用的操作
public void add(int index,E e){
if(index<0||index>size){
throw new IllegalArgumentException("Add failed,Illegal index");
}
Node prev=dummyHead;
for (int i=0;i<index;i++){
prev=prev.next;
}
/*Node node=new Node(e);
node.next=prev.next;
prev.next=node;*/
prev.next=new Node(e,prev.next);
size++;
}
//在链表末尾添加新的元素e
public void addLast(E e){
add(size,e);
}
//在链表的第index
public E get(int index){
if(index<0||index>=size){
throw new IllegalArgumentException("Get failed,Illegal index");
}
Node cur=dummyHead.next;
for (int i=0;i<index;i++){
cur=cur.next;
}
return cur.e;
}
//获取链表的第一个元素
public E getFirst(){
return get(0);
}
public E getLast(){
return get(size-1);
}
public void set(int index,E e){
if(index<0||index>=size){
throw new IllegalArgumentException("Set failed,Illegal index");
}
Node cur=dummyHead.next;
for (int i=0;i<index;i++){
cur=cur.next;
}
cur.e=e;
}
//从链表中删除元素e
public void removeElement(E e){
//查找元素,查找到则退出
Node prev=dummyHead;
while (prev.next!=null){
if(prev.next.e.equals(e)){
break;
}
prev=prev.next;
}
if(prev.next!=null){
Node delNode=prev.next;
prev.next=delNode.next;
delNode.next=null;
}
}
//查找链表中是否有元素e
public boolean contains(E e){
Node cur=dummyHead.next;
while (cur!=null){
if(cur.e.equals(e)){
return true;
}
cur=cur.next;
}
return false;
}
@Override
public String toString(){
StringBuilder res=new StringBuilder();
/*Node cur=dummyHead.next;
while (cur!=null){
res.append(cur+"->");
cur=cur.next;
}*/
for (Node cur=dummyHead.next;cur!=null;cur=cur.next){
res.append(cur+"->");
}
res.append("NULL");
return res.toString();
}
//从链表中删除index位置的元素
public E remove(int index){
if(index<0||index>=size){
throw new IllegalArgumentException("Set failed,Illegal index");
}
Node prev=dummyHead;
for (int i=0;i<index;i++){
prev= prev.next;
}
Node retNode=prev.next;
prev.next=retNode.next;
retNode.next=null;
size--;
return retNode.e;
}
public E removeFirst(){
return remove(0);
}
public E removeLast(){
return remove(size-1);
}
}
算法第五章
链表与递归
递归本质上,将原来的问题,转化为更小的同一问题
递归函数的微观解读
递归函数的调用,本质是函数的调用