[2018/11/14] Java学习
在网上下载了一个用Java实现的数据结构的视频, 看了前三个视频, 感觉收获很大, 今天花了接近三小时在Java的数据结构上.
课程的目录如下:
第01讲:数组
第02讲:简单排序
第03讲:栈和队列
第04讲:链表
第05讲:双端链表和双向链表
第06讲:递归的应用
第07讲:递归的高级应用
第08讲:希尔排序
第09讲:快速排序
第10讲:二叉树的基本概念
第11讲:二叉树的基本操作
第12讲:遍历二叉树
第13讲:删除二叉树节点
第14讲:红黑树
第15讲:哈希表
第16讲:开放地址法
第17讲:链地址法
第18讲:图的基本概念
第19讲:图的搜索
第20讲:图的最小生成树
今天和昨天我看完了前三章的内容, 代码都亲手敲了一遍:
例子配套使用了测试类, 而不是将代码写在一个类里面, 这种写法非常的新颖(我以前的写法太过老土).
细节都是用private保证了类的安全性.
对于变量的使用, 太厉害了.
package ch_01; public class MyArray { private long[] arr; private int elements; /** * 初始化数组 */ public MyArray() { arr = new long[50]; } /** * 重构初始化函数, 自定义函数的长度 * @param maxsize */ public MyArray(int maxsize) { arr = new long[maxsize]; } /** * 插入数组的元素 */ public void insert(long value) { /*由于数组的最末一项的编号是elements-1, 所以可以直接通过elements来表示新加入的元素*/ arr[elements] = value; elements++; // 注意elements要后移一位, 方便下一次添加元素. } /** * 显示数组的元素 */ public void display() { System.out.print("["); for (int i = 0; i < elements; i++) { System.out.print(arr[i] + " "); } System.out.println("]"); } /** * 按照数组值搜索 */ public int search(long value) { int i; for (i = 0; i < elements; i++) { if (value == arr[i]) { break; } } if(i == elements) { // 如果遍历到最后一个序列, 注意最后一个元素的序列因该是elements-1 return -1; } else { return 1; } } /** * 按序列获取元素值 */ public long get(int index) { if (index >= elements || index < 0) { throw new ArrayIndexOutOfBoundsException(); } else { return arr[index]; } } /** * 删除数据 */ public void delete(int index) { if(index >= elements || index < 0) { throw new ArrayIndexOutOfBoundsException(); } else { for(int i = index; i < elements; i++) { arr[i] = arr[i + 1]; //写错了, 之前写成了arr[index] = arr[index + 1] //抹掉index序列的元素的值, 后面的元素整体向前移动 } elements--; // 处理后, 要将元素的数量减一 } } }
测试类:
package ch_01; public class TestArray { /** * 测试类 * @param args */ public static void main(String[] args) { MyArray arr = new MyArray(); arr.insert(10); arr.insert(20); arr.insert(90); arr.display(); System.out.println(arr.search(20)); System.out.println(arr.get(2)); arr.delete(0); arr.display(); } }
第二讲: 简单的排序
冒泡排序
插入排序
选择排序
冒泡排序:
使用双重for循环,: 最外一层是从数组的开始向后循环, 内循环是从最后向前循环, 只要序号在前的元素大于序号靠后的元素, 就交换两个元素的值. 一直到数组的最前方, 将最小的元素放到元素的首部, 依次循环, 将第二小的元素放在第二位....
上代码:
package ch_02; public class BubbleSort { public static void sort(long[] arr) { long temp = 0; for(int i = 0; i < arr.length-1; i++) { // 外层的循环从前向后 for (int j = arr.length - 1; j > i; j--) { // 内层的循环从后向前, 判断序号靠前的元素是否小于序号靠后的元素 // 如果不是, 交换位置 if (arr[j - 1] > arr[j]) { //进行交换 temp = arr[j]; arr[j] = arr[j-1]; arr[j-1] = temp; } } } } }
插入排序:
和冒泡排序类似, 使用双层循环, 外层的for循环是从1开始的, 内层的循环是while循环, 外层的循环从前向后, 内层的循环从后向前. 从第2个元素开始(数组序号是1), 和前面的所有的元素进行比较直到遇到比自己小的元素或者序列为0, 该元素之前到比他小的元素之间的所有的元素整体向后移动, 然后将元素插入到较小的元素的后面. 如此循环......
代码:
package ch_02; public class Insertsort { public static void sort(long[] arr) { long tmp = 0; for (int i = 1; i < arr.length; i++) { // 从一开始设置插入点tmp. tmp = arr[i]; int j = i; while(j > 0 && arr[j] >= tmp) { // 少了=号就不能实现功能了. // 从后向前移动, 直到数组的最前方或者是遇到一个比后面的数都小的数. arr[j] = arr[j - 1]; j--; } arr[j] = tmp; } } }
选择排序:
和冒泡排序很像, 都是使用双层的for循环, 外层的循环用来控制数组的下标, 内层的for循环使用了两个变量, 一个j用来遍历后面所有的元素, 选择出值最小的一个元素, 通过另一个变量k记录该元素的下标, 通过该变量, 和外层的循环配合使用, 将k指向的最小的元素从0排列到最后.
package ch_02; public class SelectionSort { public static void sort(long[] arr) { int k = 0; long temp = 0; for (int i = 0; i < arr.length - 1; i++) { // 这一步和冒泡排序是相同的, 都是从最前开始排序 k = i; for (int j = i; j < arr.length; j++) { if (arr[j] < arr[k]) { // 确保k是最小的元素的下标 k = j; } } temp = arr[i]; arr[i] = arr[k]; arr[k] = temp; } } }
第三部分: 栈和队列
栈先进后出, 从首部添加数组元素.
队列先进先出, 栈包括单向队列和循环队列, 从尾部添加数组元素.
栈只用一个变量top来指向数组的最上的元素.就可以实现栈的所有功能.
package ch_03; public class MyStack { private long[] arr; private int top; /** * 默认构造方法 */ public MyStack() { arr = new long[10]; top = -1; } /** * 带参数的构造方法 */ public MyStack(int maxsize) { arr = new long[maxsize]; top = -1; } /** * 添加数据 */ public void push(int value) { arr[++top] = value; } /** * 移除数据 */ public long pop() { return arr[top--]; } /** * 查看数据 */ public long peek() { return arr[top]; } /** * 判断是否为空 */ public boolean isEmpty() { return top == -1; } /** * 判断栈是否满了 */ public boolean isFull() { return top == arr.length - 1; } }
队列需要三个变量分别指代: 队列中元素的数量, 队列的首部, 队列的尾部.
package ch_03; /** * 单项队列 * @author narcisohuang * */ public class MyQueue { public long[] arr; /** * elements 有效数据的大小 * front 队列头部 * end 队列尾部 */ private int elements; private int front; private int end; /** * 默认构造方法 */ public MyQueue() { arr = new long[10]; elements = 0; front = 0; end = -1; } /** * 带参数的构造方法, 参数为数组的大小 */ public MyQueue(int maxsize) { arr = new long[maxsize]; elements = 0; front = 0; end = -1; } /** * 添加数据 */ public void insert(long value) { arr[++end] = value; //不是循环的队列, 在初始化并删除数据后, 不能再直接元素, 因为end溢出了. elements++; } /** * 删除数据, 从数组的头部删除 */ public long remove() { elements--; return arr[front++]; } /** * 查看数据, 从队列的头部开始查看 */ public long peek() { return arr[front]; } /** * 判断队列是否空 */ public boolean isEmpty() { return elements == 0; } /** * 判断队列是否满 */ public boolean isFull() { return elements == arr.length; } }
单向队列在赋值之后, 再删除队列内的元素, 再赋值, 是不可以的, 因为, 描述队列头部的变量一直在向前增加, 第二次赋值的时候, 变量溢出了.
循环队列为了解决不和对此赋值的问题, 将描述队列的头部的变量在其元素清空后初始化为零.
上代码:
package ch_03; /** * 单项队列 * @author narcisohuang * */ public class MyCycleQueue { public long[] arr; /** * elements 有效数据的大小 * front 队列头部 * end 队列尾部 */ private int elements; private int front; private int end; /** * 默认构造方法 */ public MyCycleQueue() { arr = new long[10]; elements = 0; front = 0; end = -1; } /** * 带参数的构造方法, 参数为数组的大小 */ public MyCycleQueue(int maxsize) { arr = new long[maxsize]; elements = 0; front = 0; end = -1; } /** * 添加数据 */ public void insert(long value) { if (end == arr.length-1) { end = -1; } arr[++end] = value; elements++; } /** * 删除数据, 从数组的头部删除 */ public long remove() { long value = arr[front++]; if (front == arr.length) { front = 0; } elements--; return value; } /** * 查看数据, 从队列的头部开始查看 */ public long peek() { return arr[front]; } /** * 判断队列是否空 */ public boolean isEmpty() { return elements == 0; } /** * 判断队列是否满 */ public boolean isFull() { return elements == arr.length; } }