1.数据结构概述
数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成
存储结构
顺序存储结构
顺序存储结构:是把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。数组就是顺序存储结构的典型代表。
链式存储结构
链式存储结构:是把数据元素存放在内存中的任意存储单元里,也就是可以把数据存放在内存的各个位置。这些数据在内存中的地址可以是连续的,也可以是不连续的。
逻辑结构
集合结构
集合结构中的数据元素同属于一个集合,他们之间是并列的关系,除此之外没有其他关系。
线性结构
线性结构中的元素存在一对一的相互关系。
树形结构
树形结构中的元素存在一对多的相互关系。
图形结构
图形结构中的元素存在多对多的相互关系。
2.线性结构
数组
数组扩容
import java.util.Arrays;
public class TestOpArray {
public static void main(String[] args) {
int[] arr = new int[] {9,8,7};
System.out.println(Arrays.toString(arr));
int dst=6;
int[] newArr = new int[arr.length+1];
for(int i=0;i<arr.length;i++) {
newArr[i]=arr[i];
}
newArr[arr.length]=dst;
arr=newArr;
System.out.println(Arrays.toString(arr));
}
}
数组删除
import java.util.Arrays;
public class TestOpArray2 {
public static void main(String[] args) {
int[] arr = new int[] {9,8,7,6,5,4};
int dst = 3;
System.out.println(Arrays.toString(arr));
int[] newArr = new int[arr.length-1];
for(int i=0;i<newArr.length;i++) {
if(i<dst) {
newArr[i]=arr[i];
}else {
newArr[i]=arr[i+1];
}
}
arr=newArr;
System.out.println(Arrays.toString(arr));
}
}
面向对象的数组
查找算法-线性查找
从头到尾一个一个找即可
public class TestSearch {
public static void main(String[] args) {
int[] arr = new int[] {2,3,5,6,8,4,9,0};
int target = 10;
int index = -1;
for(int i=0;i<arr.length;i++) {
if(arr[i]==target) {
index=i;
break;
}
}
System.out.println("index:"+index);
}
}
查找算法-二分法查找
针对于有序数组,分半进行查找
public class TestBinarySearch {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5,6,7,8,9};
int target = 3;
int begin = 0;
int end = arr.length-1;
int mid = (begin+end)/2;
int index=-1;
while(true) {
if(arr[mid]==target) {
index=mid;
break;
}else {
if(arr[mid]>target) {
end=mid-1;
}else {
begin = mid+1;
}
mid=(begin+end)/2;
}
}
System.out.println("index:"+index);
}
}
栈
栈实现方式-数组
public class MyStack {
int[] elements;
public MyStack() {
elements = new int[0];
}
public void push(int element) {
int[] newArr = new int[elements.length + 1];
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}
newArr[elements.length] = element;
elements = newArr;
}
public int pop() {
if(elements.length==0) {
throw new RuntimeException("stack is empty");
}
int element = elements[elements.length-1];
int[] newArr = new int[elements.length-1];
for(int i=0;i<elements.length-1;i++) {
newArr[i]=elements[i];
}
elements=newArr;
return element;
}
public int peek() {
if(elements.length==0) {
throw new RuntimeException("stack is empty");
}
return elements[elements.length-1];
}
public boolean isEmpty() {
return elements.length==0;
}
队列
队列实现方式-数组
import javax.swing.text.DefaultStyledDocument.ElementSpec;
public class MyQueue {
int[] elements;
public MyQueue() {
elements=new int[0];
}
public void add(int element) {
int[] newArr = new int[elements.length + 1];
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}
newArr[elements.length] = element;
elements = newArr;
}
public int poll() {
int element = elements[0];
int[] newArr = new int[elements.length-1];
for(int i=0;i<newArr.length;i++) {
newArr[i]=elements[i+1];
}
elements=newArr;
return element;
}
public boolean isEmpty() {
return elements.length==0;
}
}
单链表
单链表-构建
public class Node {
int data;
Node next;
public Node(int data) {
this.data=data;
}
public Node append(Node node) {
Node currentNode = this;
while(true) {
Node nextNode = currentNode.next;
if(nextNode==null) {
break;
}
currentNode = nextNode;
}
currentNode.next=node;
return this;
}
public void after(Node node) {
Node nextNext = next;
this.next=node;
node.next=nextNext;
}
public void show() {
Node currentNode = this;
while(true) {
System.out.print(currentNode.data+" ");
currentNode=currentNode.next;
if(currentNode==null) {
break;
}
}
System.out.println();
}
public void removeNext() {
Node newNext = next.next;
this.next=newNext;
}
public Node next() {
return this.next;
}
public int getData() {
return this.data;
}
public boolean isLast() {
return next==null;
}
}
测试
public class TestNode {
public static void main(String[] args) {
Node n1 = new Node(1);
Node n2 = new Node(2);
Node n3 = new Node(3);
n1.append(n2).append(n3).append(new Node(4));
n1.show();
Node node = new Node(5);
n1.next().after(node);
n1.show();
}
}
单链表-删除节点
public void removeNext() {
Node newNext = next.next;
this.next=newNext;
}
单链表-插入节点
public void after(Node node) {
Node nextNext = next;
this.next=node;
node.next=nextNext;
}
循环链表
循环链表-构建
public class LoopNode {
int data;
LoopNode next=this;
public LoopNode(int data) {
this.data=data;
}
public void after(LoopNode node) {
LoopNode nextNext = next;
this.next=node;
node.next=nextNext;
}
public void removeNext() {
LoopNode newNext = next.next;
this.next=newNext;
}
public LoopNode next() {
return this.next;
}
public int getData() {
return this.data;
}
}
双向链表
两种如图:空的双向循环链表,非空的双向循环链表
循环双向链表-代码实现
public class DoubleNode {
DoubleNode pre=this;
DoubleNode next=this;
int data;
public DoubleNode(int data) {
this.data=data;
}
public void after(DoubleNode node) {
DoubleNode nextNext = next;
this.next=node;
node.pre=this;
node.next=nextNext;
nextNext.pre=node;
}
public DoubleNode next() {
return this.next;
}
public DoubleNode pre() {
return this.pre;
}
public int getData() {
return this.data;
}
}
递归
递归:在一个方法(函数)的内部调用该方法(函数)本身的编程方式
应用一: 斐波那契
public class TestFebonacci {
public static void main(String[] args) {
int i = febonacci(7);
System.out.println(i);
}
public static int febonacci(int i) {
if(i==1 || i==2) {
return 1;
}else {
return febonacci(i-1)+febonacci(i-2);
}
}
}
应用二 :汉诺塔问题
public class TestHanoi {
public static void main(String[] args) {
hanoi(5,'A','B','C');
}
public static void hanoi(int n,char from,char in,char to) {
if(n==1) {
System.out.println("第1个盘子从"+from+"移到"+to);
}else {
hanoi(n-1,from,to,in);
System.out.println("第"+n+"个盘子从"+from+"移到"+to);
hanoi(n-1,in,from,to);
}
}
}
3. 排序算法
时间复杂度,空间复杂度
时间复杂度
概念
一般情况下,算法中的基本操作语句的重复执行次数是问题规模n的某个函数,用T(n)表示。 若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度,简称时间复杂度。 T(n)不同,但时间复杂度可能相同。如:T(n)=n2+5n+6与T(n)=3n2+3n+2它们的T(n)不同,但时间复杂度相同,都为O(n^2)。
常见的时间复杂度
常数阶O(1) 对数阶O(log2n) 线性阶O(n) 线性对数阶O(nlog2n) 平方阶O(n2) 立方阶O(n3) k次方阶O(nk) 指数阶O(2n)
随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。
计算时间复杂度方法
用常数1代替运行时间中的所有加法常树 修改后的运行次数函数中,只保留最高阶项1 去除最高阶项的系数
平均时间复杂度和最坏时间复杂度
平均时间复杂度:是指所有可能的输入实例均以等概率出现的情况下,该算法的运行时间。 最坏情况下的时间复杂度称最坏时间复杂度:一般讨论的时间复杂度均是最坏情况下的时间复杂度。这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限这就保证了算法的运行时间不会比最坏情况更长。
空间复杂度
排序算法
### 不同算法之间比较
冒泡排序
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] arr=new int[] {5,7,2,9,4,1,0,5,7};
System.out.println(Arrays.toString(arr));
bubbleSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void bubbleSort(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;
}
}
}
}
}
快速排序
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[] arr = new int[] {3,4,6,7,2,7,2,8,0,9,1};
quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr,int start,int end) {
if(start<end) {
int stard=arr[start];
int low=start;
int high=end;
while(low<high) {
while(low<high&&stard<=arr[high]) {
high--;
}
arr[low]=arr[high];
while(low<high&&arr[low]<=stard) {
low++;
}
arr[high]=arr[low];
}
arr[low]=stard;
quickSort(arr, start, low);
quickSort(arr, low+1, end);
}
}
}
插入排序
import java.util.Arrays;
public class InsertSort {
public static void main(String[] args) {
int[] arr = new int[] {5,3,2,8,5,9,1,0};
insertSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void insertSort(int[] arr) {
for(int i=1;i<arr.length;i++) {
if(arr[i]<arr[i-1]) {
int temp=arr[i];
int j;
for(j=i-1;j>=0&&temp<arr[j];j--) {
arr[j+1]=arr[j];
}
arr[j+1]=temp;
}
}
}
}
希尔排序
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[] { 3, 5, 2, 7, 8, 1, 2, 0, 4, 7, 4, 3, 8 };
System.out.println(Arrays.toString(arr));
shellSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void shellSort(int[] arr) {
int k = 1;
for (int d = arr.length / 2; d > 0; d /= 2) {
for (int i = d; i < arr.length; i++) {
for (int j = i - d; j >= 0; j -= d) {
if (arr[j] > arr[j + d]) {
int temp = arr[j];
arr[j] = arr[j + d];
arr[j + d] = temp;
}
}
}
System.out.println("第" + k + "次排序结果:" + Arrays.toString(arr));
k++;
}
}
}
选择排序-简单选择排序
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int[] arr = new int[] {3,4,5,7,1,2,0,3,6,8};
selectSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void selectSort(int[] arr) {
for(int i=0;i<arr.length;i++) {
int minIndex=i;
for(int j=i+1;j<arr.length;j++) {
if(arr[minIndex]>arr[j]) {
minIndex=j;
}
}
if(i!=minIndex) {
int temp=arr[i];
arr[i]=arr[minIndex];
arr[minIndex]=temp;
}
}
}
}
归并排序
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int[] arr = new int[] {1,3,5,2,4,6,8,10};
System.out.println(Arrays.toString(arr));
mergeSort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void mergeSort(int[] arr,int low,int high) {
int middle=(high+low)/2;
if(low<high) {
mergeSort(arr, low, middle);
mergeSort(arr, middle+1, high);
merge(arr,low,middle,high);
}
}
public static void merge(int[] arr,int low,int middle, int high) {
int[] temp = new int[high-low+1];
int i=low;
int j=middle+1;
int index=0;
while(i<=middle&&j<=high) {
if(arr[i]<=arr[j]) {
temp[index]=arr[i];
i++;
}else {
temp[index]=arr[j];
j++;
}
index++;
}
while(j<=high) {
temp[index]=arr[j];
j++;
index++;
}
while(i<=middle) {
temp[index]=arr[i];
i++;
index++;
}
for(int k=0;k<temp.length;k++) {
arr[k+low]=temp[k];
}
}
}
基数排序
适用于大小数都有的场景
基数排序-数组方式
原理
从0->9依次取出数据 从0-9依次取出数据 依然从0->9依次取出 至此顺序已经OK 排序次数取决于数字的最大位数
实现
import java.util.Arrays;
public class RadixSort {
public static void main(String[] args) {
int[] arr = new int[] {23,6,189,45,9,287,56,1,798,34,65,652,5};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void radixSort(int[] arr) {
int max=Integer.MIN_VALUE;
for(int i=0;i<arr.length;i++) {
if(arr[i]>max) {
max=arr[i];
}
}
int maxLength = (max+"").length();
int[][] temp = new int[10][arr.length];
int[] counts = new int[10];
for(int i=0,n=1;i<maxLength;i++,n*=10) {
for(int j=0;j<arr.length;j++) {
int ys = arr[j]/n%10;
temp[ys][counts[ys]] = arr[j];
counts[ys]++;
}
int index=0;
for(int k=0;k<counts.length;k++) {
if(counts[k]!=0) {
for(int l=0;l<counts[k];l++) {
arr[index] = temp[k][l];
index++;
}
counts[k]=0;
}
}
}
}
}
基础排序-队列实现
import java.util.Arrays;
import demo2.MyQueue;
public class RadixQueueSort {
public static void main(String[] args) {
int[] arr = new int[] {23,6,189,45,9,287,56,1,798,34,65,652,5};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void radixSort(int[] arr) {
int max=Integer.MIN_VALUE;
for(int i=0;i<arr.length;i++) {
if(arr[i]>max) {
max=arr[i];
}
}
int maxLength = (max+"").length();
MyQueue[] temp = new MyQueue[10];
for(int i=0;i<temp.length;i++) {
temp[i]=new MyQueue();
}
for(int i=0,n=1;i<maxLength;i++,n*=10) {
for(int j=0;j<arr.length;j++) {
int ys = arr[j]/n%10;
temp[ys].add(arr[j]);
}
int index=0;
for(int k=0;k<temp.length;k++) {
while(!temp[k].isEmpty()) {
arr[index] = temp[k].poll();
index++;
}
}
}
}
}
public class MyQueue {
int[] elements;
public MyQueue() {
elements=new int[0];
}
public void add(int element) {
int[] newArr = new int[elements.length + 1];
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}
newArr[elements.length] = element;
elements = newArr;
}
public int poll() {
int element = elements[0];
int[] newArr = new int[elements.length-1];
for(int i=0;i<newArr.length;i++) {
newArr[i]=elements[i+1];
}
elements=newArr;
return element;
}
public boolean isEmpty() {
return elements.length==0;
}
}
4. 树
树概念
- 根节点
- 双亲节点
- 子节点
- 路径
- 节点的度
- 节点的权
- 叶子节点
- 子树
- 层
- 树的高度
- 森林
二叉树
概念
二叉树:任何一个节点的子节点数量不超2 二叉树的子节点分左节点和右节点
分类
满二叉树
完全二叉树
链式存储的二叉树
创建
public class Node {
int value;
Node leftNode;
Node rightNode;
public Node(int value) {
this.value=value;
}
public void setLeftNode(Node leftNode) {
this.leftNode = leftNode;
}
public void setRightNode(Node rightNode) {
this.rightNode = rightNode;
}
public void frontShow() {
System.out.println(value);
if(leftNode!=null) {
leftNode.frontShow();
}
if(rightNode!=null) {
rightNode.frontShow();
}
}
public void midShow() {
if(leftNode!=null) {
leftNode.midShow();
}
System.out.println(value);
if(rightNode!=null) {
rightNode.midShow();
}
}
public void afterShow() {
if(leftNode!=null) {
leftNode.afterShow();
}
if(rightNode!=null) {
rightNode.afterShow();
}
System.out.println(value);
}
public Node frontSearch(int i) {
Node target=null;
if(this.value==i) {
return this;
}else {
if(leftNode!=null) {
target = leftNode.frontSearch(i);
}
if(target!=null) {
return target;
}
if(rightNode!=null) {
target=rightNode.frontSearch(i);
}
}
return target;
}
public void delete(int i) {
Node parent = this;
if(parent.leftNode!=null&&parent.leftNode.value==i) {
parent.leftNode=null;
return;
}
if(parent.rightNode!=null&&parent.rightNode.value==i) {
parent.rightNode=null;
return;
}
parent=leftNode;
if(parent!=null) {
parent.delete(i);
}
parent=rightNode;
if(parent!=null) {
parent.delete(i);
}
}
}
public class BinaryTree {
Node root;
public void setRoot(Node root) {
this.root = root;
}
public Node getRoot() {
return root;
}
public void frontShow() {
if(root!=null) {
root.frontShow();
}
}
public void midShow() {
if(root!=null) {
root.midShow();
}
}
public void afterShow() {
if(root!=null) {
root.afterShow();
}
}
public Node frontSearch(int i) {
return root.frontSearch(i);
}
public void delete(int i) {
if(root.value==i) {
root=null;
}else {
root.delete(i);
}
}
}
测试
public class TestBinaryTree {
public static void main(String[] args) {
BinaryTree binTree = new BinaryTree();
Node root = new Node(1);
binTree.setRoot(root);
Node rootL = new Node(2);
root.setLeftNode(rootL);
Node rootR = new Node(3);
root.setRightNode(rootR);
rootL.setLeftNode(new Node(4));
rootL.setRightNode(new Node(5));
rootR.setLeftNode(new Node(6));
rootR.setRightNode(new Node(7));
binTree.frontShow();
System.out.println("===============");
binTree.midShow();
System.out.println("===============");
binTree.afterShow();
System.out.println("===============");
Node result = binTree.frontSearch(5);
System.out.println(result);
System.out.println("===============");
binTree.delete(4);
binTree.frontShow();
}
}
遍历
- 前序遍历
- 中序遍历
- 后序遍历
前序遍历
见【构建】代码里面
中序遍历
见【构建】代码里面
后序遍历
见【构建】代码里面
查找
查找也有三种方法(前序/中序/后序查找) 示例前序方式
见【构建】代码里面
删除
见【构建】代码里面
顺序存储的二叉树
顺序存储的二叉树通常只考虑完全二叉树
性质
遍历
public class ArrayBinaryTree {
int[] data;
public ArrayBinaryTree(int[] data) {
this.data=data;
}
public void frontShow() {
frontShow(0);
}
public void frontShow(int index) {
if(data==null||data.length==0) {
return;
}
System.out.println(data[index]);
if(2*index+1<data.length) {
frontShow(2*index+1);
}
if(2*index+2<data.length) {
frontShow(2*index+2);
}
}
}
测试
public class TestArrayBinaryTree {
public static void main(String[] args) {
int[] data = new int[] {1,2,3,4,5,6,7};
ArrayBinaryTree tree = new ArrayBinaryTree(data);
tree.frontShow();
}
}
堆
概念
大顶堆:所有父节点都大于其子节点 小顶堆:所欲父节点都小于其子节点
升序排序使用大顶堆 降序排序使用小顶堆
大顶堆示例:
二叉树转为大顶堆
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] arr = new int[] {9,6,8,7,0,1,10,4,2};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void heapSort(int[] arr) {
int start = (arr.length-1)/2;
for(int i=start;i>=0;i--) {
maxHeap(arr, arr.length, i);
}
for(int i=arr.length-1;i>0;i--) {
int temp = arr[0];
arr[0]=arr[i];
arr[i]=temp;
maxHeap(arr, i, 0);
}
}
public static void maxHeap(int[] arr,int size,int index) {
int leftNode = 2*index+1;
int rightNode = 2*index+2;
int max = index;
if(leftNode<size&&arr[leftNode]>arr[max]) {
max=leftNode;
}
if(rightNode<size&&arr[rightNode]>arr[max]) {
max=rightNode;
}
if(max!=index) {
int temp=arr[index];
arr[index]=arr[max];
arr[max]=temp;
maxHeap(arr, size, max);
}
}
}
堆排序 通过转成大顶堆,然后用第一位和最后一位交换,交换后的最后一位即是最大值
堆排序
通过转成大顶堆,然后用第一位和最后一位交换,交换后的最后一位即是最大值
public static void heapSort(int[] arr) {
int start = (arr.length-1)/2;
for(int i=start;i>=0;i--) {
maxHeap(arr, arr.length, i);
}
for(int i=arr.length-1;i>0;i--) {
int temp = arr[0];
arr[0]=arr[i];
arr[i]=temp;
maxHeap(arr, i, 0);
}
}
线索二叉树
概念
形成一个双向链表 中序/前序/后序线索化二叉树
实现
public class ThreadedNode {
int value;
ThreadedNode leftNode;
ThreadedNode rightNode;
int leftType;
int rightType;
public ThreadedNode(int value) {
this.value=value;
}
public void setLeftNode(ThreadedNode leftNode) {
this.leftNode = leftNode;
}
public void setRightNode(ThreadedNode rightNode) {
this.rightNode = rightNode;
}
public void frontShow() {
System.out.println(value);
if(leftNode!=null) {
leftNode.frontShow();
}
if(rightNode!=null) {
rightNode.frontShow();
}
}
public void midShow() {
if(leftNode!=null) {
leftNode.midShow();
}
System.out.println(value);
if(rightNode!=null) {
rightNode.midShow();
}
}
public void afterShow() {
if(leftNode!=null) {
leftNode.afterShow();
}
if(rightNode!=null) {
rightNode.afterShow();
}
System.out.println(value);
}
public ThreadedNode frontSearch(int i) {
ThreadedNode target=null;
if(this.value==i) {
return this;
}else {
if(leftNode!=null) {
target = leftNode.frontSearch(i);
}
if(target!=null) {
return target;
}
if(rightNode!=null) {
target=rightNode.frontSearch(i);
}
}
return target;
}
public void delete(int i) {
ThreadedNode parent = this;
if(parent.leftNode!=null&&parent.leftNode.value==i) {
parent.leftNode=null;
return;
}
if(parent.rightNode!=null&&parent.rightNode.value==i) {
parent.rightNode=null;
return;
}
parent=leftNode;
if(parent!=null) {
parent.delete(i);
}
parent=rightNode;
if(parent!=null) {
parent.delete(i);
}
}
}
public class ThreadedBinaryTree {
ThreadedNode root;
ThreadedNode pre=null;
public void threadIterate() {
ThreadedNode node = root;
while(node!=null) {
while(node.leftType==0) {
node=node.leftNode;
}
System.out.println(node.value);
while(node.rightType==1) {
node=node.rightNode;
System.out.println(node.value);
}
node=node.rightNode;
}
}
public void setRoot(ThreadedNode root) {
this.root = root;
}
public void threadNodes() {
threadNodes(root);
}
public void threadNodes(ThreadedNode node) {
if(node==null) {
return;
}
threadNodes(node.leftNode);
if(node.leftNode==null){
node.leftNode=pre;
node.leftType=1;
}
if(pre!=null&&pre.rightNode==null) {
pre.rightNode=node;
pre.rightType=1;
}
pre=node;
threadNodes(node.rightNode);
}
public ThreadedNode getRoot() {
return root;
}
public void frontShow() {
if(root!=null) {
root.frontShow();
}
}
public void midShow() {
if(root!=null) {
root.midShow();
}
}
public void afterShow() {
if(root!=null) {
root.afterShow();
}
}
public ThreadedNode frontSearch(int i) {
return root.frontSearch(i);
}
public void delete(int i) {
if(root.value==i) {
root=null;
}else {
root.delete(i);
}
}
}
public class TestThreadedBinaryTree {
public static void main(String[] args) {
ThreadedBinaryTree binTree = new ThreadedBinaryTree();
ThreadedNode root = new ThreadedNode(1);
binTree.setRoot(root);
ThreadedNode rootL = new ThreadedNode(2);
root.setLeftNode(rootL);
ThreadedNode rootR = new ThreadedNode(3);
root.setRightNode(rootR);
rootL.setLeftNode(new ThreadedNode(4));
ThreadedNode fiveNode = new ThreadedNode(5);
rootL.setRightNode(fiveNode);
rootR.setLeftNode(new ThreadedNode(6));
rootR.setRightNode(new ThreadedNode(7));
binTree.midShow();
System.out.println("===============");
binTree.threadNodes();
binTree.threadIterate();
}
}
遍历
public void threadIterate() {
ThreadedNode node = root;
while(node!=null) {
while(node.leftType==0) {
node=node.leftNode;
}
System.out.println(node.value);
while(node.rightType==1) {
node=node.rightNode;
System.out.println(node.value);
}
node=node.rightNode;
}
}
赫夫曼树
概念
最优二叉树:它是n个带权叶子结点构成的所有二叉树中,带权路径长度最小的二叉树。 叶节点的带权路径 树的带权路径长度WPL:树的带权路径长度WPL(weighted path length):树中所有叶子结点的带权路径长度之和。 (a)WPL=9x2+4x2+5x2+2x2=18+8+10+4=40 (b)WPL=9x1+5x2+4x3+2x3=9+10+12+6=37 (c)WPL=4x1+2x2+5x3+9x3=4+4+15+27=50 权值越大的结点离根结点越近的二叉树才是最优二叉树。
构建方式
最终结构即为:赫夫曼树
代码实现
- 统计字符数并排序
- 创建赫夫曼树
- 创建赫夫曼编码表
- 编码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestHuffmanTree {
public static void main(String[] args) {
int[] arr = {3,7,8,29,5,11,23,14};
Node node = createHuffmanTree(arr);
System.out.println(node);
}
public static Node createHuffmanTree(int[] arr) {
List<Node> nodes = new ArrayList<>();
for(int value:arr) {
nodes.add(new Node(value));
}
while(nodes.size()>1) {
Collections.sort(nodes);
Node left = nodes.get(nodes.size()-1);
Node right = nodes.get(nodes.size()-2);
Node parent = new Node(left.value+right.value);
nodes.remove(left);
nodes.remove(right);
nodes.add(parent);
}
return nodes.get(0);
}
}
public class Node implements Comparable<Node> {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
@Override
public int compareTo(Node o) {
return -(this.value - o.value);
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
}
赫夫曼编码
赫夫曼编码-代码实现
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class TestHuffmanCode {
public static void main(String[] args) {
String src="1.bmp";
String dst="2.zip";
try {
unZip("2.zip", "3.bmp");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void unZip(String src,String dst) throws Exception {
InputStream is = new FileInputStream("2.zip");
ObjectInputStream ois = new ObjectInputStream(is);
byte[] b = (byte[]) ois.readObject();
Map<Byte, String> codes = (Map<Byte, String>) ois.readObject();
ois.close();
is.close();
byte[] bytes = decode(codes, b);
OutputStream os = new FileOutputStream(dst);
os.write(bytes);
os.close();
}
public static void zipFile(String src,String dst) throws IOException {
InputStream is = new FileInputStream(src);
byte[] b = new byte[is.available()];
is.read(b);
is.close();
byte[] byteZip = huffmanZip(b);
OutputStream os = new FileOutputStream(dst);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(byteZip);
oos.writeObject(huffCodes);
oos.close();
os.close();
}
private static byte[] decode(Map<Byte, String> huffCodes, byte[] bytes) {
StringBuilder sb = new StringBuilder();
for(int i=0;i<bytes.length;i++) {
byte b = bytes[i];
boolean flag = (i==bytes.length-1);
sb.append(byteToBitStr(!flag,b));
}
Map<String, Byte> map = new HashMap<>();
for(Map.Entry<Byte, String> entry:huffCodes.entrySet()) {
map.put(entry.getValue(), entry.getKey());
}
List<Byte> list = new ArrayList<>();
for(int i=0;i<sb.length();) {
int count=1;
boolean flag = true;
Byte b=null;
while(flag) {
String key = sb.substring(i, i+count);
b = map.get(key);
if(b==null) {
count++;
}else {
flag=false;
}
}
list.add(b);
i+=count;
}
byte[] b = new byte[list.size()];
for(int i=0;i<b.length;i++) {
b[i]=list.get(i);
}
return b;
}
private static String byteToBitStr(boolean flag,byte b) {
int temp=b;
if(flag) {
temp|=256;
}
String str = Integer.toBinaryString(temp);
if(flag) {
return str.substring(str.length()-8);
}else {
return str;
}
}
private static byte[] huffmanZip(byte[] bytes) {
List<Node> nodes = getNodes(bytes);
Node tree = createHuffmanTree(nodes);
Map<Byte, String> huffCodes = getCodes(tree);
byte[] b = zip(bytes,huffCodes);
return b;
}
private static byte[] zip(byte[] bytes, Map<Byte, String> huffCodes) {
StringBuilder sb = new StringBuilder();
for(byte b:bytes) {
sb.append(huffCodes.get(b));
}
int len;
if(sb.length()%8==0) {
len=sb.length()/8;
}else {
len=sb.length()/8+1;
}
byte[] by = new byte[len];
int index = 0;
for(int i=0;i<sb.length();i+=8) {
String strByte;
if(i+8>sb.length()) {
strByte = sb.substring(i);
}else {
strByte = sb.substring(i, i+8);
}
byte byt = (byte)Integer.parseInt(strByte, 2);
by[index]=byt;
index++;
}
return by;
}
static StringBuilder sb = new StringBuilder();
static Map<Byte, String> huffCodes = new HashMap<>();
private static Map<Byte, String> getCodes(Node tree) {
if(tree==null) {
return null;
}
getCodes(tree.left,"0",sb);
getCodes(tree.right,"1",sb);
return huffCodes;
}
private static void getCodes(Node node, String code, StringBuilder sb) {
StringBuilder sb2 = new StringBuilder(sb);
sb2.append(code);
if(node.data==null) {
getCodes(node.left, "0", sb2);
getCodes(node.right, "1", sb2);
}else {
huffCodes.put(node.data, sb2.toString());
}
}
private static Node createHuffmanTree(List<Node> nodes) {
while(nodes.size()>1) {
Collections.sort(nodes);
Node left = nodes.get(nodes.size()-1);
Node right = nodes.get(nodes.size()-2);
Node parent = new Node(null, left.weight+right.weight);
parent.left=left;
parent.right=right;
nodes.remove(left);
nodes.remove(right);
nodes.add(parent);
}
return nodes.get(0);
}
private static List<Node> getNodes(byte[] bytes) {
List<Node> nodes = new ArrayList<>();
Map<Byte, Integer> counts = new HashMap<>();
for(byte b:bytes) {
Integer count = counts.get(b);
if(count==null) {
counts.put(b, 1);
}else {
counts.put(b, count+1);
}
}
for(Map.Entry<Byte, Integer> entry:counts.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
return nodes;
}
}
public class Node implements Comparable<Node> {
Byte data;
int weight;
Node left;
Node right;
public Node(Byte data,int weight) {
this.data=data;
this.weight=weight;
}
@Override
public String toString() {
return "Node [data=" + data + ", weight=" + weight + "]";
}
@Override
public int compareTo(Node o) {
return o.weight-this.weight;
}
}
二叉查找树
概念
二叉查找树,插入或查找性能都较好 中序遍历二叉查找树,是从小到大的特性
实现
public class BinarySortTree {
Node root;
public void add(Node node){
if(root==null) {
root=node;
}else {
root.add(node);
}
}
public void midShow() {
if(root!=null) {
root.midShow(root);
}
}
public Node search(int value) {
if(root==null) {
return null;
}else {
return root.search(value);
}
}
public void delete(int value) {
if(root==null) {
return;
}else {
Node target = search(value);
if(target==null) {
return;
}
Node parent = searchParent(value);
if(target.left==null&&target.right==null) {
if(parent.left.value==value) {
parent.left=null;
}else {
parent.right=null;
}
}else if(target.left!=null&&target.right!=null) {
int min = deleteMin(target.right);
target.value=min;
}else {
if(target.left!=null) {
if(parent.left.value==value) {
parent.left=target.left;
}else {
parent.right=target.left;
}
}else {
if(parent.left.value==value) {
parent.left=target.right;
}else {
parent.right=target.right;
}
}
}
}
}
private int deleteMin(Node node) {
Node target = node;
while(target.left!=null) {
target=target.left;
}
delete(target.value);
return target.value;
}
public Node searchParent(int value) {
if(root==null) {
return null;
}else {
return root.searchParent(value);
}
}
}
AVL树
概念
左子树和右子树高度的绝对值不超过1
单旋转:左旋/右旋;
双旋转:左旋/右旋
实现
public class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value=value;
}
public int height() {
return Math.max(left==null?0:left.height(), right==null?0:right.height())+1;
}
public int leftHeight() {
if(left==null) {
return 0;
}
return left.height();
}
public int rightHeight() {
if(right==null) {
return 0;
}
return right.height();
}
public void add(Node node) {
if(node==null) {
return;
}
if(node.value<this.value) {
if(this.left==null) {
this.left=node;
}else {
this.left.add(node);
}
}else {
if(this.right==null) {
this.right=node;
}else {
this.right.add(node);
}
}
if(leftHeight()-rightHeight()>=2) {
if(left!=null&&left.leftHeight()<left.rightHeight()) {
left.leftRotate();
rightRotate();
}else {
rightRotate();
}
}
if(leftHeight()-rightHeight()<=-2) {
if(right!=null&&right.rightHeight()<right.leftHeight()) {
right.rightRotate();
leftRotate();
}else {
leftRotate();
}
}
}
private void leftRotate() {
Node newLeft = new Node(value);
newLeft.left=left;
newLeft.right=right.left;
value=right.value;
right=right.right;
left=newLeft;
}
private void rightRotate() {
Node newRight = new Node(value);
newRight.right=right;
newRight.left=left.right;
value=left.value;
left=left.left;
right=newRight;
}
public void midShow(Node node) {
if(node==null) {
return;
}
midShow(node.left);
System.out.println(node.value);
midShow(node.right);
}
public Node search(int value) {
if(this.value==value) {
return this;
}else if(value<this.value) {
if(left==null) {
return null;
}
return left.search(value);
}else{
if(right==null) {
return null;
}
return right.search(value);
}
}
public Node searchParent(int value) {
if((this.left!=null&&this.left.value==value)||(this.right!=null&&this.right.value==value)) {
return this;
}else {
if(this.value>value&&this.left!=null) {
return this.left.searchParent(value);
}else if(this.value<value&&this.right!=null){
return this.right.searchParent(value);
}
return null;
}
}
}
public class BinarySortTree {
Node root;
public void add(Node node){
if(root==null) {
root=node;
}else {
root.add(node);
}
}
public void midShow() {
if(root!=null) {
root.midShow(root);
}
}
public Node search(int value) {
if(root==null) {
return null;
}else {
return root.search(value);
}
}
public void delete(int value) {
if(root==null) {
return;
}else {
Node target = search(value);
if(target==null) {
return;
}
Node parent = searchParent(value);
if(target.left==null&&target.right==null) {
if(parent.left.value==value) {
parent.left=null;
}else {
parent.right=null;
}
}else if(target.left!=null&&target.right!=null) {
int min = deleteMin(target.right);
target.value=min;
}else {
if(target.left!=null) {
if(parent.left.value==value) {
parent.left=target.left;
}else {
parent.right=target.left;
}
}else {
if(parent.left.value==value) {
parent.left=target.right;
}else {
parent.right=target.right;
}
}
}
}
}
private int deleteMin(Node node) {
Node target = node;
while(target.left!=null) {
target=target.left;
}
delete(target.value);
return target.value;
}
public Node searchParent(int value) {
if(root==null) {
return null;
}else {
return root.searchParent(value);
}
}
}
public class TestBinarySortTree {
public static void main(String[] args) {
int[] arr = new int[] {8,9,5,4,6,7};
BinarySortTree bst = new BinarySortTree();
for(int i:arr) {
bst.add(new Node(i));
}
System.out.println(bst.root.height());
System.out.println(bst.root.value);
}
}
多路查找树
2-3树/2-3-4树
B树
B+树
5. 哈希表
概念
散列函数
- 直接定址法
- 数字分析法
- 平方取中法
- 取余法
- 随机数法
直接定址法-代码实现:
import java.util.Arrays;
public class HashTable {
private StuInfo[] data = new StuInfo[100];
public void put(StuInfo stuInfo) {
int index = stuInfo.hashCode();
data[index]=stuInfo;
}
public StuInfo get(StuInfo stuInfo) {
return data[stuInfo.hashCode()];
}
@Override
public String toString() {
return "HashTable [data=" + Arrays.toString(data) + "]";
}
}
public class StuInfo {
private int age;
private int count;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int hashCode() {
return age;
}
public StuInfo(int age, int count) {
super();
this.age = age;
this.count = count;
}
public StuInfo(int age) {
super();
this.age = age;
}
@Override
public String toString() {
return "StuInfo [age=" + age + ", count=" + count + "]";
}
}
public class TestHashTable {
public static void main(String[] args) {
StuInfo s1 = new StuInfo(16, 3);
StuInfo s2 = new StuInfo(17, 11);
StuInfo s3 = new StuInfo(18, 23);
StuInfo s4 = new StuInfo(19, 24);
StuInfo s5 = new StuInfo(20, 9);
HashTable ht = new HashTable();
ht.put(s1);
ht.put(s2);
ht.put(s3);
ht.put(s4);
ht.put(s5);
System.out.println(ht);
StuInfo target = new StuInfo(18);
StuInfo info = ht.get(target);
System.out.println(info);
}
}
散列冲突解决方案
6. 图
概念
实现
import demo2.MyStack;
public class Graph {
private Vertex[] vertex;
private int currentSize;
public int[][] adjMat;
private MyStack stack = new MyStack();
private int currentIndex;
public Graph(int size) {
vertex=new Vertex[size];
adjMat=new int[size][size];
}
public void addVertex(Vertex v) {
vertex[currentSize++]=v;
}
public void addEdge(String v1,String v2) {
int index1=0;
for(int i=0;i<vertex.length;i++) {
if(vertex[i].getValue().equals(v1)) {
index1=i;
break;
}
}
int index2=0;
for(int i=0;i<vertex.length;i++) {
if(vertex[i].getValue().equals(v2)) {
index2=i;
break;
}
}
adjMat[index1][index2]=1;
adjMat[index2][index1]=1;
}
public void dfs() {
vertex[0].visited=true;
stack.push(0);
System.out.println(vertex[0].getValue());
out:while(!stack.isEmpty()) {
for(int i=currentIndex+1;i<vertex.length;i++) {
if(adjMat[currentIndex][i]==1&&vertex[i].visited==false) {
stack.push(i);
vertex[i].visited=true;
System.out.println(vertex[i].getValue());
continue out;
}
}
stack.pop();
if(!stack.isEmpty()) {
currentIndex=stack.peek();
}
}
}
}
import java.util.Arrays;
public class TestGraph {
public static void main(String[] args) {
Vertex v1 = new Vertex("A");
Vertex v2 = new Vertex("B");
Vertex v3 = new Vertex("C");
Vertex v4 = new Vertex("D");
Vertex v5 = new Vertex("E");
Graph g = new Graph(5);
g.addVertex(v1);
g.addVertex(v2);
g.addVertex(v3);
g.addVertex(v4);
g.addVertex(v5);
g.addEdge("A", "C");
g.addEdge("B", "C");
g.addEdge("A", "B");
g.addEdge("B", "D");
g.addEdge("B", "E");
for(int[] a:g.adjMat) {
System.out.println(Arrays.toString(a));
}
g.dfs();
}
}
public class Vertex {
private String value;
public boolean visited;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Vertex(String value) {
super();
this.value = value;
}
@Override
public String toString() {
return value;
}
}
public class MyStack {
int[] elements;
public MyStack() {
elements = new int[0];
}
public void push(int element) {
int[] newArr = new int[elements.length + 1];
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}
newArr[elements.length] = element;
elements = newArr;
}
public int pop() {
if(elements.length==0) {
throw new RuntimeException("stack is empty");
}
int element = elements[elements.length-1];
int[] newArr = new int[elements.length-1];
for(int i=0;i<elements.length-1;i++) {
newArr[i]=elements[i];
}
elements=newArr;
return element;
}
public int peek() {
if(elements.length==0) {
throw new RuntimeException("stack is empty");
}
return elements[elements.length-1];
}
public boolean isEmpty() {
return elements.length==0;
}
}
遍历方式
深度优先搜索算法-栈实现
广度优先搜索算法-队列实现
|