第 1 章:为什么要学
为什么要学
程序=算法+数据结构
1.在数据结构和算法有着短板的人。无论笔试还是面试只要涉及到数据结构和算法都会将自己的短板给暴露出来,即使自己在别的方面比较优秀,如果面试官问的不是很全面的话很容易给自己造成不利的影响,多多少少都给面试官留下不是很好的印象。2.不确定要学哪门语言的人。数据结构、算法通用型较强。无论是做ios开发,andriod开发,java,C++ …等开发,具备较好的数据结构、算法知识很多时候都是自己的一大助力。无论将来流行什么语言,但是我们可知的是,数据结构和算法将永生,对于我们开发者来说学习数据结构和算法的性价比还是挺高的。
3.对人工智能感兴趣的人。人工智能核心在算法,对计算机专业基础知识有着较高的要求,这些都要求在数据结构、算法等方面有较高的知识素养。
4.想成为专家型开发者。工作几年,对自己的定位更加明确,希望自己能够称为一名专家型的开发者,这就要求你在工作中遇到问题不仅要知其然还要知其所以然,不仅如此,对于某些功能、效果的实现,甚至要有独到的见解,而这些都要求你要有一个好的数据结构和算法知识。
第 2 章:初识算法
自定义集合
定义MyArray.class
1、定义一个成员变量数组,首先必须要有长度,其次定义一个长度
public class MyArray {
//定义内部数组
private int[] arr;
//数组的有效长度
private int elements;
public MyArray() {
this(50);
}
public MyArray(int maxSize) {
arr = new int[maxSize];
}
/**
* 增加
*
* @param value
*/
public void insert(int value) {
arr[elements] = value;
elements++;
}
/**
* 打印数组
*/
public void display() {
for (int i = 0; i < elements; i++) {
System.out.print(arr[i]);
}
}
/**
* 根据值查询
*
* @param value
* @return
*/
public int search(long value) {
int i;
for (i = 0; i < elements; i++) {
if (arr[i] == value) {
break;
}
}
if (i == elements) {
return -1;
} else {
return i;
}
}
/**
* 根据索引查找值
*
* @param index
* @return
*/
public int get(int index) {
if (index >= elements || index < 0) {
throw new IndexOutOfBoundsException();
} else {
return arr[index];
}
}
/**
* 根据索引删除数据
*
* @param index
* @return
*/
public int delete(int index) {
if (index >= elements || index < 0) {
throw new IndexOutOfBoundsException();
}
int retVal = arr[index];
for (int i = index; i < elements - 1; i++) {
//把i+1索引上的元素,覆盖前面的一个元素
arr[i] = arr[i + 1];
}
elements--;
return retVal;
}
/**
* 根据索引修改数据
*
* @param index
* @return
*/
public void change(int index, int newValue) {
if (index >= elements || index < 0) {
throw new IndexOutOfBoundsException();
} else {
arr[index] = newValue;
}
}
}
自定义排序数组
/**
* 增加
*
* @param value
*/
public void insert(int value) {
int i;
for (i = 0; i < elements; i++) {
if (arr[i] > value) {
break;
}
}
for (int j = elements; j > i; j--) {
arr[j] = arr[j - 1];
}
arr[i] = value;
elements++;
}
二分法查找
/**
* 二分法查找
*
* @param value
*/
public int binarySearch(int value) {
int low = 0;
int mid=0;
int high = arr.length;
while (low <= high) {
mid = (low + high) / 2;
if (arr[mid] == value) {
return mid;
} else if (arr[mid] > value) {
high = mid - 1;
} else if (arr[mid] < value) {
low = mid + 1;
}
}
return -1;
}
冒泡排序
/**
* 冒泡排序
*
* @param arr
*/
public void sort(int[] arr) {
for (int i = arr.length - 1; i > 0; --i) {
for (int j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/**
* 冒泡排序
*
* @param arr
*/
public void sort2(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
选择排序
/**
* 选择排序
*
* @param arr
*/
public void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
插入排序
/**
* 插入排序
*
* @param arr
*/
public void sort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
//判断索引为1的值,和前面的值进行比较,判断谁大
if (arr[i - 1] > arr[i]) {
//更换位置
int temp = arr[i];
//k表示前面的值
int k = i - 1;
while (k >= 0 && arr[k] > temp) {
arr[k + 1] = arr[k];
k = k - 1;
}
arr[k + 1] = temp;
}
}
}
三种排序效率对比
冒泡<选择<插入
自定义栈
public class MyStack {
//定义一个数组
private int[] arr;
//记录栈顶的位置
private int top;
public MyStack() {
arr = new int[10];
//默认情况下top为-1,表示没有值
top = -1;
}
public MyStack(int max) {
arr = new int[max];
//默认情况下top为-1,表示没有值
top = -1;
}
/**
* 添加一个值
*
* @param vlaue
*/
public void push(int vlaue) {
arr[++top] = value;
}
/**
* 移除一个值
*
* @return
*/
public int pop() {
return arr[top--];
}
/**
* 查看数据
*
* @return
*/
public int peek() {
return arr[top];
}
/**
* 判断当前是否为空
* @return
*/
public boolean isEmpty() {
return top == -1;
}
/**
* 判断当前栈是否满了
* @return
*/
public boolean isFull(){
return top==arr.length-1;
}
}
自定义队列
会出现下标越界异常
public class MyQueue {
//队头
private int front;
//队尾
private int end;
//数组
private int[] arr;
//记录元素个数
private int elements;
public MyQueue() {
arr = new int[10];
elements = 0;
front = 0;
end = -1;
}
public MyQueue(int maxSize) {
arr = new int[maxSize];
elements = 0;
front = 0;
end = -1;
}
/**
* 在队尾插入一个值
*
* @param value
*/
public void insert(int value) {
arr[++end] = value;
elements++;
}
/**
* 在队头删除一个值
*/
public int remove() {
elements--;
return arr[front++];
}
/**
* 从队头查看数据
*
* @return
*/
public int peek() {
return arr[front];
}
/**
* 判断当前数组是否有值
*
* @return
*/
public boolean isEmpty() {
return elements == 0;
}
/**
* 判断当前数组是否已经满了
*
* @return
*/
public boolean isFull() {
return arr.length == elements;
}
}
自定义同步队列
public class MyCycleQueue {
//队头
private int front;
//队尾
private int end;
//数组
private int[] arr;
//记录元素个数
private int elements;
public MyCycleQueue() {
arr = new int[10];
elements = 0;
front = 0;
end = -1;
}
public MyCycleQueue(int maxSize) {
arr = new int[maxSize];
elements = 0;
front = 0;
end = -1;
}
/**
* 在队尾插入一个值
*
* @param value
*/
public void insert(int value) {
if (end == arr.length - 1) {
end = -1;
}
arr[++end] = value;
elements++;
}
/**
* 在队头删除一个值
*/
public int remove() {
int value = arr[front++];
if (front == arr.length) {
front = 0;
}
elements--;
return value;
}
/**
* 从队头查看数据
*
* @return
*/
public int peek() {
return arr[front];
}
/**
* 判断当前数组是否有值
*
* @return
*/
public boolean isEmpty() {
return elements == 0;
}
/**
* 判断当前数组是否已经满了
*
* @return
*/
public boolean isFull() {
return arr.length == elements;
}
}
自定义单端链表一
public class MyLinkedTable {
//头节点
private Node first;
/**
* 添加头部节点
*/
public void addFirst(int data) {
//一个链表都没有
if (first == null) {
first = new Node(data);
return;
}
//生成新的节点
Node node = new Node(data);
//让新增加的节点的next指向之前的头结点
node.next = first;
//将first节点指向新节点
first = node;
}
/**
* 遍历当前所有节点
*/
public void dispaly() {
Node current = first;
while (current.next != null) {
System.out.print(current.data);
current = current.next;
}
}
}
自定义单端链表二
自定义单端链表三
public class MyLinkedTable {
//头节点
private Node first;
/**
* 添加头部节点
*/
public void addFirst(int data) {
//一个链表都没有
if (first == null) {
first = new Node(data);
return;
}
//生成新的节点
Node node = new Node(data);
//让新增加的节点的next指向之前的头结点
node.next = first;
//将first节点指向新节点
first = node;
}
/**
* 添加尾部节点
*
* @param data
*/
public void addLast(int data) {
Node node = new Node(data);
if (first == null) {
first = node;
return;
}
Node currentNode = first;
while (currentNode.next != null) {
currentNode = currentNode.next;
}
currentNode.next = node;
}
/**
* 遍历当前所有节点
*/
public void dispaly() {
Node current = first;
while (current.next != null) {
System.out.print(current.data);
current = current.next;
}
}
/**
* 删除头结点
*
* @return
*/
public Node removeFirst() {
//一个节点都没有的情况
if (first == null) {
return null;
}
Node node = first;
//让当前头结点的下一个节点指向头节点
first = first.next;
return node;
}
/**
* 删除尾结点
*
* @return
*/
public Node removeLast() {
//一个节点都没有的情况
if (first == null) {
return null;
}
//如果只有一个节点
if (first.next == null) {
first = null;
return first;
}
//有两个和两个以上
//当前节点
Node currentNode = first;
//最后一个节点的上一个节点
Node previousNode = first;
while (currentNode.next != null) {
previousNode = currentNode;
currentNode = currentNode.next;
}
previousNode.next = null;
return currentNode;
}
/**
* 根据数据查找节点
*
* @param data
* @return
*/
public Node find(int data) {
if (first == null) {
return null;
}
Node currentNode = first;
while (currentNode != null) {
if (currentNode.data == data) {
return currentNode;
}
currentNode = currentNode.next;
}
return null;
}
/**
* 根据数据删除节点
*
* @param data
* @return
*/
public Node remove(int data) {
if (first == null) {
return null;
}
Node currentNode = first;
Node previousNode = first;
while (currentNode.data != data) {
previousNode = currentNode;
currentNode = currentNode.next;
if (currentNode == null) {
return null;
}
}
//如果代码执行到这,说明跳出循环,也有可能没进入到循环
if (currentNode == previousNode) {
Node returnNode = first;
this.first = this.first.next;
return returnNode;
}
//进入了循环并且还能执行到这,说明找到值了
previousNode.next = currentNode.next;
return currentNode;
}
}
自定义双端链表一
public class FirstLastLinkedTable {
public Node first;
public Node last;
/**
* 添加一个头部节点
*/
public void addFirst(int data) {
if (first == null) {
first = new Node(data);
last = first;
return;
}
//生成新的节点
Node node = new Node(data);
node.next = first;
first = node;
return;
}
/**
* 添加一个尾部节点
*/
public void addLast(int data) {
if (first == null) {
first = new Node(data);
last = first;
return;
}
//生成新的节点
Node node = new Node(data);
last.next=node;
last = node;
return;
}
/**
* 遍历所有的节点
*/
public void display(){
Node currentNode=first;
while(currentNode!=null){
Log.i("-----",""+currentNode.date);
currentNode=currentNode.next;
}
}
}
自定义双端链表二
public class FirstLastLinkedTable {
public Node first;
public Node last;
/**
* 删除头部节点
*
* @return
*/
public Node deleteFirst() {
if (first == null) {
return null;
}
//说明只有一个节点
if (first.next == null) {
Node returnNode = first;
first = null;
last = null;
return returnNode;
}
Node returnNode = first;
first = first.next;
return returnNode;
}
/**
* 删除头部节点
*
* @return
*/
public Node deleteLast() {
if (first == null) {
return null;
}
//说明只有一个节点
if (first.next == null) {
Node returnNode = last;
first = null;
last = null;
return returnNode;
}
Node currentNode = first;
while (currentNode.next != last) {
currentNode = currentNode.next;
}
currentNode.next = null;
Node returnNode = last;
last = currentNode;
return returnNode;
}
/**
* 添加一个头部节点
*/
public void addFirst(int data) {
if (first == null) {
first = new Node(data);
last = first;
return;
}
//生成新的节点
Node node = new Node(data);
node.next = first;
first = node;
return;
}
/**
* 添加一个尾部节点
*/
public void addLast(int data) {
if (first == null) {
first = new Node(data);
last = first;
return;
}
//生成新的节点
Node node = new Node(data);
last.next = node;
last = node;
return;
}
/**
* 遍历所有的节点
*/
public void display() {
Node currentNode = first;
while (currentNode != null) {
Log.i("-----", "" + currentNode.date);
currentNode = currentNode.next;
}
}
}
自定义双端链表三
public class FirstLastLinkedTable {
public Node first;
public Node last;
/**
* 根据数据域进行删除
*
* @param data
* @return
*/
public Node delete(int data) {
if (first == null) {
return null;
}
//如果只有一个节点
if (first.next == null) {
if (first.date == data) {
Node returnNode = first;
first = null;
last = null;
return returnNode;
}
}
//如果有多个节点,第一个节点就找到了
if (first.date == data) {
Node returnNode = first;
first = returnNode.next;
return returnNode;
}
Node currentNode = first;
Node previousNode = first;
while (currentNode.date != data) {
previousNode = currentNode;
currentNode = currentNode.next;
if (currentNode == null) {
return null;
}
}
if (currentNode == last) {
previousNode.next = null;
last = previousNode;
} else {
previousNode.next=currentNode.next;
}
return currentNode;
}
/**
* 删除头部节点
*
* @return
*/
public Node deleteFirst() {
if (first == null) {
return null;
}
//说明只有一个节点
if (first.next == null) {
Node returnNode = first;
first = null;
last = null;
return returnNode;
}
Node returnNode = first;
first = first.next;
return returnNode;
}
/**
* 删除头部节点
*
* @return
*/
public Node deleteLast() {
if (first == null) {
return null;
}
//说明只有一个节点
if (first.next == null) {
Node returnNode = last;
first = null;
last = null;
return returnNode;
}
Node currentNode = first;
while (currentNode.next != last) {
currentNode = currentNode.next;
}
currentNode.next = null;
Node returnNode = last;
last = currentNode;
return returnNode;
}
/**
* 添加一个头部节点
*/
public void addFirst(int data) {
if (first == null) {
first = new Node(data);
last = first;
return;
}
//生成新的节点
Node node = new Node(data);
node.next = first;
first = node;
return;
}
/**
* 添加一个尾部节点
*/
public void addLast(int data) {
if (first == null) {
first = new Node(data);
last = first;
return;
}
//生成新的节点
Node node = new Node(data);
last.next = node;
last = node;
return;
}
/**
* 遍历所有的节点
*/
public void display() {
Node currentNode = first;
while (currentNode != null) {
Log.i("-----", "" + currentNode.date);
currentNode = currentNode.next;
}
}
}
自定义双向链表
public class DoubleLinkedTable {
/**
* 头结点
*/
public Node first;
/**
* 尾结点
*/
public Node last;
/**
* 添加头部节点
*
* @param data
*/
public void addFirst(int data) {
if (first == null) {
first = new Node(data);
last = first;
return;
}
//生成新的节点
Node node = new Node(data);
node.next = first;
first.prev=node;
first = node;
}
/**
* 添加尾部节点
*
* @param data
*/
public void addLast(int data) {
if (first == null) {
first = new Node(data);
last = first;
return;
}
//生成新的节点
Node node = new Node(data);
node.prev=last;
last.next=node;
last=node;
}
/**
* 删除头部节点
*
* @return
*/
public Node deleteFirst() {
if (first == null) {
return null;
}
//说明只有一个节点
if (first.next == null) {
Node returnNode = first;
first = null;
last = null;
return returnNode;
}
Node returnNode = first;
first = first.next;
first.prev=null;
return returnNode;
}
/**
* 删除尾部节点
*
* @return
*/
public Node deleteLast() {
if (first == null) {
return null;
}
//说明只有一个节点
if (first.next == null) {
Node returnNode = first;
first = null;
last = null;
return returnNode;
}
Node returnNode = last;
last.prev.next=null;
last=returnNode.prev;
return returnNode;
}
}
递归原理
三角函数
public class Triangle {
/**
* 第 N 项 的 值 = 第 N-1 项 的 值 + N 的 数 列
* N: 1 2 3 4 n
* f(n)1 3 6 10 f(n-1)+n
*/
public static int getNumber(int n) {
int total = 0;
while (n > 0) {
total = total + n;
n--;
}
return total;
}
public static int f(int n) {
if (n == 1) {
return 1;
} else {
return n + f(n - 1);
}
}
}
斐波那契数列
public class Fibonacci {
/**
* 第N项等于第N-1项的值加上第N-2项的值
*
* @param n
* @return
*/
public static int getNumber(int n) {
if (n == 1) {
return 0;
} else if (n == 2) {
return 1;
} else {
return getNumber(n - 1) + getNumber(n - 2);
}
}
}
汉诺塔
public class HanoiTower {
/**
* @param topN 表示哪一个盘子
* @param from 表示盘子从哪一个塔座出发
* @param inter 中间塔座
* @param to 目的塔座
*/
public static void hanoiTower(int topN, char from, char inter, char to) {
if (topN == 1) {
System.out.print("盘子1从塔座" + from + "移动到塔座" + to);
} else {
hanoiTower(topN - 1, from, to, inter);
System.out.print("盘子" + topN + "从塔座" + from + "移动到" + to);
hanoiTower(topN - 1, inter, from, to);
}
}
}
希尔排序
排过一轮之后:
直到h=1的时候结束排序
h>0
希尔排序原理
public class ShellSort {
public static void sort(int[] arr) {
for (int h = arr.length / 2; h > 0; h = h / 2) {
for (int i = h; i < arr.length; i++) {
//通过临时变量进行记录
int temp = arr[i];
int k = i - h;
while (k >= 0 && arr[k] > temp) {
arr[k + h] = arr[k];
k = k - h;
}
arr[k + h] = temp;
}
}
}
}
快速排序原理
快速排序分区
快速排序完成
public class QuicSort {
/**
* 数组进行分区
*
* @param arr 需要进行分区的数组
* @param left 左边的指针
* @param right 右边的指针
* @param point 参照物
*/
public static int partition(int[] arr, int left, int right, int point) {
//左边从-1开始
int leftPrt = left - 1;
//右边的部分从数组的长度+1开始
int rightPrt = right;
while (true) {
//从左边的指针,从左往右找,找到第一个比关键字大的数,就停止
while (leftPrt < rightPrt && arr[++leftPrt] < point) ;
//右边的指针,从右边往左找,找到第一个比关键字小的数,就停止
while (leftPrt < rightPrt && arr[--rightPrt] > point) ;
if (leftPrt < rightPrt) {
int temp = arr[leftPrt];
arr[leftPrt] = arr[rightPrt];
arr[rightPrt] = temp;
} else {
int temp = arr[leftPrt];
arr[leftPrt] = arr[rightPrt];
arr[rightPrt] = temp;
return leftPrt;
}
}
}
public static void sort(int[] arr, int left, int right) {
if (left >= right) {
return;
}
//将数组的最后一个元素当做关键字
int point = arr[right];
//返回对数组进行分区,并且把分区点返回
int partition = partition(arr, left, right, point);
//对左边进行排序
sort(arr, left, partition - 1);
//对右边进行排序
sort(arr, partition + 1, right);
}
}
二叉树的概念
二叉树添加节点
public class Node {
//左边的孩子
private Node leftChild;
//右边的孩子
private Node rightChild;
private int data;
private Node(int data) {
this.data = data;
}
}
二叉树遍历
public class Tree {
private Node root;
public void insert(int data) {
if (root == null) {
root = new Node(data);
return;
}
//表示当前节点
Node currentNode = root;
//标记记录指针在左边还是右边
boolean isLeft = true;
//父节点
Node parent = root;
while (currentNode != null) {
parent = currentNode;
if (data < currentNode.data) {
currentNode = currentNode.leftChild;
isLeft = true;
} else {
currentNode = currentNode.rightChild;
isLeft = false;
}
}
if (isLeft) {
parent.leftChild = new Node(data);
} else {
parent.rightChild = new Node(data);
}
}
}