算法概述
- 算法(Algorithm)
一系列程序指令,用于处理特定的运算和逻辑问题。
衡量算法优劣的标准:- 时间复杂度
- 空间复杂度
- 数据结构(Data structure)
数据的组织管理和储存格式,使用目的是为了高效的访问和修改数据。
不同的算法会选用不同的数据结构。- 线性结构(数组,链表,栈,队列,哈希表)
- 树(二叉树,二叉堆)
- 图
- 其他数据结构
- 时间复杂度
T(n)=O(f(n))
O(1)<O(logn)<O(n)<O(nlogn)<O(n^2) - 空间复杂度
S(n)=O(f(n))- 四种情况
- 常量空间O(1)
- 线性空间O(n)
- 二维空间O(n^2)
- 递归空间(方法调用栈)O(n)
- 四种情况
数据结构基础
数据结构的操作无非增删改查
- 数组(array)
有限个相同类型变量组成的有序集合。
物理储存方式是顺序存储,访问是随机访问(根据下标的方式叫做)。
下标查找O(1),中间插入和删除O(n)。
适合读操作多,写操作少的场景
package chapter2.part1;
/**
* Created by weimengshu on 2018/8/24.
*/
public class MyArray {
private int[] array;
private int size;
public MyArray(int capacity){
this.array = new int[capacity];
size = 0;
}
/**
* 数组插入元素
* @param index 插入的位置
* @param element 插入的元素
*/
public void insert(int index, int element) throws Exception {
//判断访问下标是否超出范围
if(index<0 || index>size){
throw new IndexOutOfBoundsException("超出数组实际元素范围!");
}
//如果实际元素达到数组容量上线,数组扩容
if(size >= array.length){
resize();
}
//从右向左循环,逐个元素向右挪一位。
for(int i=size-1; i>=index; i--){
array[i+1] = array[i];
}
//腾出的位置放入新元素
array[index] = element;
size++;
}
/**
* 数组扩容
*/
public void resize(){
int[] arrayNew = new int[array.length*2];
//从旧数组拷贝到新数组
System.arraycopy(array, 0, arrayNew, 0, array.length);
array = arrayNew;
}
/**
* 数组删除元素
* @param index 删除的位置
*/
public int delete(int index) throws Exception {
//判断访问下标是否超出范围
if(index<0 || index>=size){
throw new IndexOutOfBoundsException("超出数组实际元素范围!");
}
int deletedElement = array[index];
//从左向右循环,逐个元素向左挪一位。
for(int i=index; i<size-1; i++){
array[i] = array[i+1];
}
size--;
return deletedElement;
}
/**
* 输出数组
*/
public void output(){
for(int i=0; i<size; i++){
System.out.println(array[i]);
}
}
public static void main(String[] args) throws Exception {
MyArray myArray = new MyArray(4);
myArray.insert(0,3);
myArray.insert(1,7);
myArray.insert(2,9);
myArray.insert(3,5);
myArray.insert(1,6);
myArray.insert(5,8);
myArray.delete(3);
myArray.output();
}
}
- 链表(linked list)
链式数据结构,由若干节点构成,每个节点包含下一节点的指针。
头节点(Head)——尾部(NULL)
物理储存方式是随机存储,访问时顺序访问。
查找节点O(n),中间插入和删除O(1)。
适合写操作多,读操作少的场景- 单向链表:节点(node)——数据(data),下一个节点的指针(next)
- 双向链表:节点(node)——数据(data),前后节点的指针(prev,next)
- 逻辑结构
- 线性结构:顺序表,栈,队列
- 非线性结构:树,图
- 物理结构
- 顺序存储结构:数组
- 链式存储结构:链表
package chapter2.part2;
/**
* Created by weimengshu on 2018/8/24.
*/
public class MyLinkedList {
//头节点指针
private Node head;
//尾节点指针
private Node last;
//链表实际长度
private int size;
/**
* 链表插入元素
* @param index 插入位置
* @param data 插入元素
*/
public void insert(int index, int data) throws Exception {
if (index<0 || index>size) {
throw new IndexOutOfBoundsException("超出链表节点范围!");
}
Node insertedNode = new Node(data);
if(size == 0){
//空链表
head = insertedNode;
last = insertedNode;
} else if(index == 0){
//插入头部
insertedNode.next = head;
head = insertedNode;
}else if(size == index){
//插入尾部
last.next = insertedNode;
last = insertedNode;
}else {
//插入中间
Node prevNode = get(index-1);
insertedNode.next = prevNode.next;
prevNode.next = insertedNode;
}
size++;
}
/**
* 链表删除元素
* @param index 删除的位置
*/
public Node remove(int index) throws Exception {
if (index<0 || index>=size) {
throw new IndexOutOfBoundsException("超出链表节点范围!");
}
Node removedNode = null;
if(index == 0){
//删除头节点
removedNode = head;
head = head.next;
}else if(index == size-1){
//删除尾节点
Node prevNode = get(index-1);
removedNode = prevNode.next;
prevNode.next = null;
last = prevNode;
}else {
//删除中间节点
Node prevNode = get(index-1);
Node nextNode = prevNode.next.next;
removedNode = prevNode.next;
prevNode.next = nextNode;
}
size--;
return removedNode;
}
/**
* 链表查找元素
* @param index 查找的位置
*/
public Node get(int index) throws Exception {
if (index<0 || index>=size) {
throw new IndexOutOfBoundsException("超出链表节点范围!");
}
Node temp = head;
for(int i=0; i<index; i++){
temp = temp.next;
}
return temp;
}
/**
* 输出链表
*/
public void output(){
Node temp = head;
while (temp!=null) {
System.out.println(temp.data);
temp = temp.next;
}
}
/**
* 链表节点
*/
private static class Node {
int data;
Node next;
Node(int data) {
this.data = data;
}
}
public static void main(String[] args) throws Exception {
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.insert(0,3);
myLinkedList.insert(0,4);
myLinkedList.insert(2,9);
myLinkedList.insert(3,5);
myLinkedList.insert(1,6);
myLinkedList.remove(0);
myLinkedList.output();
}
}
- 栈(stack)
线性逻辑结构,可以用数组和链表实现。
包含入栈和出栈操作,遵循先入后出(FILO)。- 栈底(bottom),栈顶(top)
- 进栈(push),出栈(pop)
- 队列(queue)
线性逻辑结构,可以用数组和链表实现。
包含入队和出队操作,遵循先入先出(FIFO)。- 队头(front),队尾(rear)
- 入队(enqueue),出队(dequeue)
- 双端队列,优先队列等。
循环队列:队尾指针指向的位置永远空出一位
栈的应用:历史回溯(递归的逻辑的代替,面包屑导航)
队列的应用:历史重现(多线程公平锁,网络爬虫)
package chapter2.part3;
/**
* Created by weimengshu on 2018/8/24.
*/
public class MyQueue {
private int[] array;
private int front;
private int rear;
public MyQueue(int capacity){
this.array = new int[capacity];
}
/**
* 入队
* @param element 入队的元素
*/
public void enQueue(int element) throws Exception {
if((rear+1)%array.length == front){
throw new Exception("队列已满!");
}
array[rear] = element;
rear =(rear+1)%array.length;
}
/**
* 出队
*/
public int deQueue() throws Exception {
if(rear == front){
throw new Exception("队列已空!");
}
int deQueueElement = array[front];
front =(front+1)%array.length;
return deQueueElement;
}
/**
* 输出队列
*/
public void output(){
for(int i=front; i!=rear; i=(i+1)%array.length){
System.out.println(array[i]);
}
}
public static void main(String[] args) throws Exception {
MyQueue myQueue = new MyQueue(6);
myQueue.enQueue(3);
myQueue.enQueue(5);
myQueue.enQueue(6)