本篇文章是一篇读书笔记,里边记录了一些基于java代码实现的数据结构和算法
如果错误,还望大家不吝赐教
数据类型 | 操作 | 时间复杂度 |
---|---|---|
无序数组 | 插入 | O(1) |
无序数组 | 查找 | O(N) |
无序数组,有序数组 | 删除 | O(N) |
有序数组 | 插入 | O(N) |
有序数组 | 二分查找 | O(log N) |
/**
* @param key 要查找的值
* @param arr 查找范围(数组)
* @return 存在-返回下标,不存在-返回-1
* @discription 二分查找
* 二分查找的关键是,数组必须是有序数组
*/
public static Integer BinarySearch(Integer key, Integer[] arr) {
if (arr == null || arr.length <= 0) {
return -2;
}
int low = 0;
int high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (key < arr[mid]) high = mid;
else if (key > arr[mid]) low = mid;
else return mid;
}
return -1;
}
时间复杂度O(N2)
大数往后挪
每一次完整的循环可以得到一个剩余未排序的数据中的最大数
/**
* @description 冒泡排序:大数往后移动
* @param arr
* @return
*/
public static Integer[] Bubbling(Integer[] arr){
Integer temp;
for(int i=arr.length-1;i>0;i--) {
for (int j = 0; j < i; j++) {
if (arr[j] > arr[j+1]) {
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
选择排序不同于冒泡排序的区别是:比较的次数是不变样的,但是移动的次数为O(N)
/**
* @param arr
* @return
* @description 选择排序:每次选出最小的放在排头
*/
public static Integer[] chooseSort(Integer[] arr) {
Integer temp;
int index;
for (int i = 0; i < arr.length - 1; i++) {
index = i;
for (int j = i; j < arr.length - 1; j++) {
if (arr[index] > arr[j + 1])
index = j + 1;
}
if (index != i) {
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
}
return arr;
}
/**
* @description 插入排序:类似于斗地主抓牌的时候整牌的过程
* @param arr
* @return
*/
public static Integer[] insertSort(Integer[] arr) {
Integer target;
int i, j;
for (i = 1; i < arr.length; i++) {
if (arr[i] < arr[i - 1]) {
target = arr[i];
for (j = i - 1; j >= 0 && arr[j] > target; j--) {
arr[j + 1] = arr[j];
}
arr[j + 1] = target;
}
}
return arr;
}
栈:先进后出
队列:先进先出
经典示例:计算算数表达式
① 把中缀表达式解析成后缀表达式,运算符入栈
② 计算后缀表达式,操作数入栈
4.1 栈
栈
import java.lang.reflect.Array;
public class MyStack<E> {
// 栈顶坐标
private int top;
// 栈长度
private int maxSize;
private E[] stackArr;
public MyStack(int maxSize){
this.maxSize = maxSize;
this.top = -1;
this.stackArr = (E[]) Array.newInstance(Object.class,maxSize);
}
// 入栈
public void push(E ch){
stackArr[++top] = ch;
}
// 出栈
public E pop(){
return stackArr[top--];
}
// 查看栈顶元素
public E peek(){
return stackArr[top];
}
// 判空
public boolean isEmpty(){
return top == -1;
}
// 判满
public boolean isFull(){
return top == (maxSize-1);
}
// 栈实际长度
public int size(){
return top+1;
}
public void display(){
System.out.println("出栈顺序:");
while (top>=0){
System.out.print("->" + pop());
}
System.out.println();
}
}
中缀表达式转换成后缀表达式
public class InToPostfixExpression {
private MyStack<Character> myStack;
private String inPut;
private String outPut="";
public InToPostfixExpression(String inPut){
this.inPut = inPut;
int stackSize = inPut.length();
this.myStack = new MyStack(stackSize);
}
public String doPost(){
for(int i=0;i<inPut.length();i++){
char ch = inPut.charAt(i);
switch (ch){
case '-':
case '+':
dealOption(ch,1);
break;
case '*':
case '/':
dealOption(ch,2);
break;
case '(':
myStack.push('(');
break;
case ')':
dealBrackets();
break;
default:
outPut += ch;
}
}
while (!myStack.isEmpty()){
outPut += myStack.pop();
}
outPut = outPut.replaceAll(" "," ");
return outPut;
}
private void dealOption(char thisOption,int grade){
int oldGrade;
while (! myStack.isEmpty()){
char topOption = myStack.pop();
if(topOption == '('){
myStack.push(topOption);
break;
}else{
if(topOption == '-' || topOption == '+')
oldGrade = 1;
else
oldGrade =2;
if(oldGrade < grade){
myStack.push(topOption);
break;
}else
outPut += topOption;
}
}
myStack.push(thisOption);
}
public void dealBrackets(){
while (! myStack.isEmpty()){
char topOption = myStack.pop();
if(topOption == '('){
break;
}else {
outPut += topOption;
}
}
}
public String getOutPut() {
return outPut;
}
}
计算后缀表达式
public class Calculate {
private String input;
private Integer result;
private MyStack<Integer> myStack;
public Calculate(String input){
int maxSize = input.length();
this.input = input;
this.myStack = new MyStack(maxSize);
}
public Integer doCalculate(){
int num1;
int num2;
for(int i=0;i<input.length();i++){
char opThis = input.charAt(i);
if(opThis >= '0' && opThis <= '9'){
myStack.push(Integer.parseInt(String.valueOf(opThis)));
}else {
num2 = myStack.pop();
num1 = myStack.pop();
switch (opThis){
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
if(num2 != 0){
result = num1 / num2;
break;
}else {
result = null;
}
break;
default:
result=0;
}
myStack.push(result);
}
}
return result;
}
}
public class MyQueue<E> {
private int front; // 队首
private int rear; // 队尾
private E[] queueArr; // 存储结构-数组
private int maxSize; // 队列最大长度
private int nItems; // 队列中数据项个数
public MyQueue(int size){
this.maxSize = size;
queueArr = (E[]) Array.newInstance(Object.class,size);
front=0;
rear = -1;
nItems =0;
}
public void insert(E item){
if(rear == maxSize -1){
rear = -1;
}
queueArr[++rear] = item;
nItems ++;
}
public E remove(){
E result = queueArr[front++];
if(front == maxSize -1)
front = 0;
nItems --;
return result;
}
public E peekFront(){
return queueArr[front];
}
public boolean isEmpty(){
return nItems == 0;
}
public boolean isFull(){
return nItems == maxSize;
}
public int size(){
return nItems;
}
public void display(){
System.out.println("MQ-QUEUE: Front->Rear");
Arrays.asList(queueArr).stream().forEach(item -> System.out.print("->"+item));
System.out.println();
}
}
import java.lang.reflect.InvocationTargetException;
public class Link1<E> {
public E item;
public Link1<E> next;
public Link1(E item) throws IllegalAccessException, InstantiationException {
this.item = item;
}
public void displayLink() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
System.out.print(" { "+item.getClass() .getMethod("display").invoke(item)+" }");
}
}
import java.lang.reflect.InvocationTargetException;
public class LinkList1<E> {
private Link1<E> first;
public LinkList1(){
first = null;
}
public boolean isEmpty(){
return first == null;
}
public void insertLink(E item) throws InstantiationException, IllegalAccessException {
Link1 newLink = new Link1(item);
newLink.next = first;
first = newLink;
}
public Link1 deleteFirst(){
Link1 temp = first;
first = first.next;
return temp;
}
public void displayList() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
System.out.println("LINK-LIST: REAR -> FRONT");
Link1 current = first;
while (current != null){
current.displayLink();
current = current.next;
}
}
}
import java.lang.reflect.InvocationTargetException;
public class DoubleEndedLinkedList<E> {
private Link1<E> firstLink;
private Link1<E> lastLink;
public DoubleEndedLinkedList(){
firstLink = null;
lastLink = null;
}
public boolean isEmpty(){
return firstLink == null;
}
public void insertFirst(E item) throws InstantiationException, IllegalAccessException {
Link1 link1 = new Link1(item);
if(isEmpty())
lastLink = link1;
link1.next = firstLink;
firstLink = link1;
}
public void insertLast(E item) throws InstantiationException, IllegalAccessException {
Link1 link1 = new Link1(item);
if(isEmpty()) firstLink = link1;
else lastLink.next = link1;
lastLink = link1;
}
public E delFirst(){
E item = firstLink.item;
if(firstLink.next == null)
lastLink = null;
firstLink = firstLink.next;
return item;
}
public void display() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
System.out.println("First -> Last");
Link1 current = firstLink;
while (current!=null){
current.displayLink();
current = current.next;
}
System.out.println();
}
}
public class LinkInteger {
private Integer key;
public LinkInteger next;
public LinkInteger(Integer item){
this.key = item;
next = null;
}
public Integer getKey() {
return key;
}
public void displayNode(){
System.out.print(key+" ");
}
}
public class SortLink {
private LinkInteger first;
public SortLink(){
first = null;
}
public boolean isEmpty(){
return first == null;
}
public void insert(Integer item) {
LinkInteger newLink = new LinkInteger(item);
LinkInteger previous = null;
LinkInteger current = first;
while ((current != null) && item > current.getKey()){
previous = current;
current = current.next;
}
if(previous==null) {
first = newLink;
}else {
previous.next = newLink;
}
newLink.next = current;
}
public LinkInteger remove(){
LinkInteger temp = first;
first = first.next;
return temp;
}
public void display() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
System.out.println("LINK-LIST: REAR -> FRONT");
LinkInteger current = first;
while (current != null){
current.displayNode();
current = current.next;
}
}
}
public class DoublyLinkNode {
private Integer key;
public DoublyLinkNode previous;
public DoublyLinkNode next;
public DoublyLinkNode(Integer key){
this.key = key;
}
public Integer getKey() {
return key;
}
public void display(){
System.out.print(key+" ");
}
}
public class DoublyLinkList {
private DoublyLinkNode first;
private DoublyLinkNode last;
public DoublyLinkList(){
first = null;
last = null;
}
public boolean isEmpty(){
return first == null;
}
public void insertFirst(Integer key){
DoublyLinkNode newNode = new DoublyLinkNode(key);
if(isEmpty())
last = newNode;
else
first.previous = newNode;
newNode.next = first;
first = newNode;
}
public void insertLast(Integer key){
DoublyLinkNode newNode = new DoublyLinkNode(key);
if(isEmpty())
first = newNode;
else{
last.next = newNode;
newNode.previous = last;
}
last = newNode;
}
public void orderInsert(Integer key){
DoublyLinkNode newNode = new DoublyLinkNode(key);
DoublyLinkNode temp = null;
DoublyLinkNode current = first;
if(first == null){
first = newNode;
}else {
while (current != null && current.getKey() <= key){
temp = current;
current = current.next;
}
if(temp == null){
current.previous = newNode;
newNode.next = current;
first = newNode;
}else if(current == null){
temp.next = newNode;
newNode.previous = temp;
last = newNode;
}else{
temp.next = newNode;
newNode.previous = temp;
newNode.next = current;
current.previous = newNode;
}
}
}
public DoublyLinkNode delFirstNode(){
DoublyLinkNode temp= first;
if(first.next == null)
last = null;
else
first.next.previous = null;
first = first.next;
return temp;
}
public DoublyLinkNode delLastNode(){
DoublyLinkNode temp = last;
if(last.previous == null)
first = null;
else {
last.previous.next = null;
}
last = last.previous;
return temp;
}
public DoublyLinkNode delKey(Integer key){
DoublyLinkNode current = first;
while (current.getKey() != key){
current = current.next;
if(current == null)
return null;
}
if(current .equals(first)){
first = current.next;
}else {
current.previous.next = current.next;
}
if(current.equals(last)){
last = current.previous;
}else {
current.next.previous = current.previous;
}
return current;
}
public void displayForward(){
DoublyLinkNode current = first;
System.out.println("display by forward:");
while (current!=null){
current.display();
current = current.next;
}
System.out.println();
}
public void displayBackward(){
DoublyLinkNode current = last;
System.out.println("display by backward:");
while (current!=null){
current.display();
current = current.previous;
}
System.out.println();
}
}
抽象数据类型(ADT,Abstract Data Type)可以先理解什么是数据类型,然后来理解抽象。
int,double都属于数据类型,数据类型一般涉及两个部分:数据(拥有特定数据项的集合)+操作(在数据上可以完成的动作)
对于Java来说,数据类型能很好的对应成类,成员变量(数据)+方法(操作)
列表:也叫做线性表,是一组线性排列的数据项。它是一种抽象,可以通过链表和数组实现
可用来解决特定问题:三角数字、汉诺塔、阶乘、生成变位字
简单来说,递归就是自己调用自己
递归可以转换成一个基于栈的非递归方法
采用递归往往是从概念上简化了问题,而不是因为本质上提高了效率
一个数字序列:1、3、6、10、15、21、、、
第 N 项 = 第 ( N − 1 ) 项 + N 或 者 第 N 项 = 1 + 2 + 3 + . . . + N 第N项 = 第(N-1)项 + N 或者 第N项 = 1 + 2 + 3 + ... + N 第N项=第(N−1)项+N或者第N项=1+2+3+...+N
/**
* @description 求第N个三角数字
* @param n
* @return
*/
public static int triangle(int n){
if(n == 1){
return 1;
}else {
return (n + triangle(n-1));
}
}
/**
* @description 求N的阶乘
* @param n
* @return
*/
public static int factorial(int n){
if(n==0){
return 1;
}else {
return (n * factorial(n-1));
}
}
/**
* @description 递归-二分查找
* @param arr 已排序的数组
* @param key 要查询的值
* @param lowerBound [lowerBound,upperBound]
* @param upperBound
* @return
*/
public static int binarySearch(int[] arr,int key,int lowerBound,int upperBound){
int currentIndex = lowerBound+(upperBound-lowerBound)/2;
if(lowerBound > upperBound){
return -1;
}
if(arr[currentIndex] == key){
return currentIndex;
}
if(arr[currentIndex] > key){
return binarySearch(arr,key,lowerBound,currentIndex-1);
}
if(arr[currentIndex] < key){
return binarySearch(arr,key,currentIndex+1,upperBound);
}
return -1;
}
汉诺塔:共需要移动 2n -1
/**
* @description 汉诺塔问题
* @param dishNum
* @param from
* @param temp
* @param to
*/
public static void dealHanoi(int dishNum,char from,char temp,char to){
if(dishNum == 1){
System.out.println("dishNum 1 from "+from+" to "+to);
}else {
dealHanoi(dishNum-1,from,to,temp);
System.out.println("dishNum " +dishNum + " from "+from+" to "+to);
dealHanoi(dishNum-1,temp,from,to);
}
}
/**
* @description 归并排序
* @param arrA 原数组A
* @param arrB 原数组B
* @param arrC 归并后有序数组C
* @param sizeA 数组A的长度
* @param sizeB 数组B的长度
*/
public static Integer[] mergeSort(int[] arrA,int[] arrB,Integer[] arrC,int sizeA,int sizeB){
int indexA=0,indexB=0,indexC=0;
while(indexA < sizeA && indexB <sizeB){
if(arrA[indexA] < arrB[indexB]){
arrC[indexC++] = arrA[indexA++];
}else {
arrC[indexC++] = arrB[indexB++];
}
}
while (indexA < sizeA){
arrC[indexC++] = arrA[indexA++];
}
while (indexB < sizeB){
arrC[indexC++] = arrB[indexB++];
}
return arrC;
}
希尔排序、快速排序
希尔排序的时间复杂度是O(N * (logN)2)。
原理:
① 使用 h = h ∗ 3 + 1 h = h*3 + 1 h=h∗3+1来获取最大间隔h,
② 做增量为h的增量排序,直到h递减到1,
③ 每次增量排序后,都达到“基本有序”
/**
* @description 希尔排序
* 由来:插入排序的弊端是,移动的步长是1,如果元素a要插入到长度为N的升序数组中,元素a要移动N次
* 希尔排序中定义了一个数列:h=h*3+1;
* @param arr
* @return
*/
public static Integer[] shellSort(Integer[] arr){
int outer,inner,h=1;
Integer temp;
// 1 求出最大步长
while (h <= arr.length/3)
h = h*3 +1;
// 2 排序
while (h>0){
for(outer=h;outer<arr.length;outer++){
inner = outer;
temp = arr[outer];
while (inner >h-1 && arr[inner-h]>temp){
arr[inner] = arr[inner-h];
inner -= h;
}
arr[inner] = temp;
}
h = (h-1)/3;
}
return arr;
}
时间复杂度:O(N * logN)
核心思想是:递归调用划分算法
/**
* * 快速排序
* * 核心思想:划分算法
* *
*/
public static Integer[] quickSort(Integer[] arr,int minIndex,int maxIndex){
if(maxIndex-minIndex<=0){
return arr;
}else{
Integer pivot = arr[maxIndex];
int partition = partitionIt(arr,minIndex,maxIndex,pivot);
quickSort(arr,minIndex,partition-1);
quickSort(arr,partition+1,maxIndex);
}
return arr;
}
public static int partitionIt(Integer[] arr,int minIndex,int maxIndex,Integer pivot){
int leftPtr = minIndex -1;
int rightPtr = maxIndex;
while (true){
while (arr[++leftPtr]<pivot);
while (rightPtr>0 && arr[--maxIndex]>pivot);
if(leftPtr>=rightPtr){
break;
}else {
swap(arr,leftPtr,rightPtr);
}
}
swap(arr,leftPtr,maxIndex);
return leftPtr;
}
private static void swap(Integer[] arr, int leftPtr, int rightPtr) {
Integer temp = arr[leftPtr];
arr[leftPtr] = arr[rightPtr];
arr[rightPtr] = temp;
}
二叉树兼并了两种数据结构的优点:可以像有序数组一样快速查找 + 像链表一样快速插入和删除