数据结构和算法整理笔记(持续更新)

数据结构和算法

参考视频:https://www.bilibili.com/video/av79558651

1、数组

封装一个集合MyOrderArray

package cn.xiaov;

/**
 * 有序集合
 */
public class MyOrderArray {

    private int[] arr;

    //有效数据的长度
    private int size;

    public MyOrderArray() {
        arr = new int[10];
    }

    public MyOrderArray(int maxSize) {
        arr = new int[maxSize];
    }

    /**
     * 添加数据
     *
     * @param value
     */
    public void add(int value) {
         //判断数组长度是否够
        if (size>=arr.length){
            //不够,扩容
            int[] temp = new int[arr.length * 2];
            System.arraycopy(arr,0,temp,0,size);
            arr=temp;
        }
        //够,直接按顺序加数据
        int i;
        for (i = 0; i < size; i++) {
            if (value < arr[i]) {
                break;
            }
        }
        for (int j = size; j > i; j--) {
            arr[j] = arr[j - 1];
        }
        arr[i++] = value;
    }

    /**
     * 显示所有
     */
    public String toString() {
        String temp = "";
        for (int i = 0; i < size; i++) {
            temp += arr[i] + " ";
        }
        return this.getClass().getSimpleName() + " = [ " + temp + "]";
    }

    /**
     * 根据下标查询数据
     *
     * @param index
     */
    public int get(int index) {
        if (index >= size || index < 0) {
            throw new ArrayIndexOutOfBoundsException();
        } else {
            return arr[index];
        }
    }

    /**
     * 二分法查找数据
     * 返回数据的下标
     *
     * @param value
     * @return
     */
    public int binarySearch(int value) {
        int middle = 0;
        int low = 0;
        int pow = size;

        while (true) {
            middle = (low + pow) / 2;
            if (arr[middle] == value) {
                return middle;
            } else if (low > pow) {
                throw new IndexOutOfBoundsException();
            } else if (arr[middle] < value) {
                low = middle + 1;
            } else if (arr[middle] > value) {
                pow = middle - 1;
            }
        }
    }

    /**
     * 判断:如果包含指定元素,则返回 true;否者返回false
     *
     * @param value
     * @return
     */
    public boolean contains(int value) {
        for (int i = 0; i < size; i++) {
            if (value == arr[i]) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据索引删除数据
     *
     * @param index
     * @return
     */
    public int remove(int index) {
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException();
        } else {
            for (int i = index; i < size; i++) {
                arr[i] = arr[i + 1];
            }
            size--;
        }
        return arr[index];
    }

    /**
     * 根据索引修改数据,返回原数据
     *
     * @param index
     * @param newValue
     * @return
     */
    public int set(int index, int newValue) {
        int temp;
        if (index >= size || index < 0) {
            throw new ArrayIndexOutOfBoundsException();
        } else {
            temp = arr[index];
            arr[index] = newValue;
            return temp;
        }
    }
}

以上代码对于int[]的数组封装成MyArray集合,进行增删查改等操作。

2、排序

冒泡排序

只要是小值,就向上交换冒泡到最上面

package cn.xiaov;

public class BubbleSort {
    public static void sort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = arr.length - 1; j > i; j--) {
                if (arr[j] < arr[j - 1]) {
                    //交换位置
                    int temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                }
            }
        }
    }
}

选择排序

将最小值的下标赋值给k,将第k个和第一个交换

public class SelectionSort {
    public static void sort(int[] arr) {
        int k = 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 = j;
                }
            }
            int temp;
            temp = arr[k];
            arr[k] = arr[i];
            arr[i] = temp;
        }
    }
}

插入排序

从第二个数起,要是小于前面一个数,存入temp;前面所有大于temp的数右移一位。

package cn.xiaov;

public class InsertSort {
    public static void sort(int[] arr){
        int temp=0;
        for (int i = 1; i < arr.length; i++) {
            temp=arr[i];
            int j=i;
            while (j>0&&temp<arr[j-1]){
                arr[j]=arr[j-1];
                j--;
            }
            arr[j]=temp;
        }
    }
}

3、栈和队列

先进后出,后进先出

package cn.xiaov.stack;

public class MyStack {
    //底层是一个数组
    private int[] arr;
    //栈顶元素下标
    private int top;

    public MyStack(){
        arr=new int[10];
        top=-1;
    }
    public MyStack(int maxSize){
        arr=new int[maxSize];
        top=-1;
    }

    /**
     * 添加
     * @param value
     */
    public void push(int value){
        arr[++top]=value;
    }

    /**
     * 移除数据
     * @return
     */
    public long pop(){
        return arr[top--];
    }

    /**
     * 查看数据
     * @return
     */
    public int peek(){
        return arr[top];
    }

    /**
     * 判断是否为空
     * @return
     */
    public boolean isEmpty(){
        return top==-1;
    }

    public boolean isFull(){
        return top==arr.length-1;
    }
}

队列

先进先出,后进后出

package cn.xiaov.queue;

/**
 * 循环队列
 */
public class MyCycleQueue {
    //底层是一个数组
    private int[] arr;
    //有效数据
    private int elements;
    //队头
    private int front;
    //队尾
    private int end;

    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) {
        //如果队尾为数组最后一个值了,那么循环回-1
        if (end==arr.length-1){
            end=-1;
        }
        arr[++end] = value;
        elements++;
    }

    /**
     * 移除数据,从队头移除
     *
     * @return
     */
    public int remove() {
        int value=arr[front++];
        if (front==arr.length){
            front=0;
        }
        elements--;
        return value;
    }

    /**
     * 查看数据,从队头查看
     *
     * @return
     */
    public int peek() {
       /* if (front==arr.length){
            front=0;
        }*/
       if (elements==0){
           throw new ArrayIndexOutOfBoundsException();
       }
        return arr[front];
    }

    /**
     * 判断是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return elements == 0;
    }

    /**
     * 判断是否满了
     * @return
     */
    public boolean isFull() {
        return elements == arr.length;
    }
}

4、链表

5、递归

将大问题分解成小问题,不断调用自身。只需要给最小的值赋值就好了。

显示100以内的数

package cn.xiaov.recursion;

public class Demo1 {
    public static void main(String[] args) {
        test(100);
    }
    private static void test(int i) {
        if (i==0){
            return;
        }
        System.out.print(i+" ");
        test(i-1);
    }
}

斐波那契数列

package cn.xiaov.fibonacci;

public class FibonacciDemo {
    public static int getNum(int num){
        if (num==1){
            return 0;
        }
        if (num==2){
            return 1;
        }
        return  getNum(num-1)+getNum(num-2);
    }
}

汉诺塔(3底座,移动盘子)

package cn.xiaov.hanoitower;

/**
 * 移动盘子
 */
public class HanoiTower {
    public static void doTower(int topN,    //移动的盘子数
                               char from,   //初始的盘子位置
                               char inter,  //中间位置
                               char to){    //目标位置
        if (topN==1){
            System.out.println("盘子1从"+from+"到"+to);
        }else{
            doTower(topN-1,from,to,inter);
            System.out.println("盘子"+topN+"从"+from+"到"+to);

            doTower(topN-1, inter, from, to);
        }
    }
}

6、希尔排序

计算最大间隔,分开进行插入排序,然后减小间隔,再次排序。

package cn.xiaov;

/**
 * 希尔排序
 */
public class ShellSort {
    public static void sort(int[] arr) {
        int h = 1;
        //计算最大的长度
        while (h < arr.length / 3) {
            h = h * 3 + 1;
        }
        while (h > 0) {
            //插入排序
            int temp = 0;
            for (int i = h; i < arr.length; i++) {
                temp = arr[i];
                int j = i;
                while (j > h-1 && temp < arr[j - h]) {
                    arr[j] = arr[j - h];
                    j -= h;
                }
                arr[j] = temp;
            }
            //减小间隔
            h = (h - 1) / 3;
        }
        for (var temp :
                arr) {
            System.out.print(temp+" ");
        }
    }
}

7、快速排序

选择最右边的数字为基数,左指针移动,大于基数交换位置,移动右指针,小于基数交换位置,一趟完成。
调用自身,基数左边,基数右边。递归到最后。

package cn.xiaov;

public class QuickSort {
    public static int[] sort(int[] arr, int start, int end) {
        int leftPtr = start;
        int rightPtr = end;
        int point = arr[end];
        while (leftPtr < rightPtr) {
            //左指针向右移动,直到大于point停止
            while (leftPtr < rightPtr && arr[leftPtr] < point) {
                leftPtr++;
            }
            //右指针向左移动,直到小于point停止
            while (leftPtr < rightPtr && arr[rightPtr] > point) {
                rightPtr--;
            }
            //两指针相遇,或者值相同
            if (leftPtr < rightPtr && arr[leftPtr] == arr[rightPtr]) {
                leftPtr++;
            } else {
                //交换leftPtr和rightPtr
                int temp;
                temp = arr[leftPtr];
                arr[leftPtr] = arr[rightPtr];
                arr[rightPtr] = temp;
            }
        }
        if (leftPtr - 1 > start) {
            sort(arr, start, leftPtr - 1);
        }

        if (rightPtr + 1 < end) {
            sort(arr, rightPtr + 1, end);
        }
        return arr;
    }
}

8、二叉树

package cn.xiaov.binarytree;

/**
 * 二叉树的节点
 */
public class Node {
    //数据项,索引
    public int data;
    //数据项
    public String sData;
    //左子节点
    public Node leftChild;
    //右子节点
    public Node rightChild;

    public Node(int value,String sData){
        this.data=value;
        this.sData=sData;
    }

}

在Tree.java中定义根节点

//根节点
public Node root;

插入节点

从根节点开始插入节点,通过判断大小,小于节点值则为左子节点,大于节点值则为右子节点。

/**
 * 增加子节点
 *
 * @param value
 * @param sData
 */
public void insert(int value, String sData) {
    Node node = new Node(value, sData);
    //引用当前节点
    Node current = root;
    //引用父节点
    Node parent;

    //如果树为空
    if (root == null) {
        root = node;
    } else {
        while (current != null) {
            parent = current;
            if (current.data > value) {
                current = current.leftChild;
                if (current == null) {
                    parent.leftChild = node;
                }
            } else {
                current = current.rightChild;
                if (current == null) {
                    parent.rightChild = node;
                }
            }
        }
    }
}

查找节点

从根节点开始查找,如果查找的节点值比当前值小,查找其左子节点,否则查找其右子节点。

/**
 * 查找子节点
 * @param value
 * @return
 */
public boolean find(int value) {
    //最开始当前节点为root
    Node current = root;
    while (current.data != value) {
        //当前值大于查找值,查找左子树
        if (current.data > value) {
            current = current.leftChild;
        } else {
            //当前值小于查找值,查找右子树
            current = current.rightChild;
        }
        if (current == null) {
            return false;
        }
    }
    return true;
}

二叉树的遍历

前序遍历
/**
 * 前序遍历
 */
public void frontOrder(Node localNode) {
    if (localNode!=null){
        //访问根节点
        System.out.println(localNode.data+", "+localNode.sData);
        //前序遍历左子树
        frontOrder(localNode.leftChild);
        //前序遍历右子树
        frontOrder(localNode.rightChild);
    }
}
中序遍历

中序遍历后,顺序为从小到大

/**
 * 中序遍历
 * @param localNode
 */
public void inOrder(Node localNode) {
    if (localNode!=null){
        //中序遍历左子树
        inOrder(localNode.leftChild);
        //访问根节点
        System.out.println(localNode.data+", "+localNode.sData);
        //中序遍历右子树
        inOrder(localNode.rightChild);
    }
}
后序遍历
/**
 * 后序遍历
 *
 * @param localNode
 */
public void afterOrder(Node localNode) {
    if (localNode != null) {
        //后序遍历左子树
        afterOrder(localNode.leftChild);
        //后序遍历右子树
        afterOrder(localNode.rightChild);
        //访问根节点
        System.out.println(localNode.data + ", " + localNode.sData);
    }
}

删除节点

/**
 * 删除子节点
 *
 * @param value
 */
public boolean delete(int value) {
    //引用当前节点,从根节点开始
    Node current = root;
    //引用父节点
    Node parent = root;
    //是否为左子节点
    boolean isLeftChild = true;

    //循环查找子节点
    while (current.data != value) {
        parent = current;
        //当前值大于查找值,查找左子树
        if (current.data > value) {
            current = current.leftChild;
            isLeftChild = true;
        } else {
            //当前值小于查找值,查找右子树
            current = current.rightChild;
            isLeftChild = false;
        }
        if (current == null) {
            //查找不到这个子节点
            return false;
        }
    }

    //查找到了节点
    if (current.leftChild == null && current.rightChild == null) {
        //如果该节点没有子节点
        if (current == root) {
            root = null;
        } else if (isLeftChild) {
            parent.leftChild = null;
        } else {
            parent.rightChild = null;
        }
    } else if (current.leftChild == null) {
        //该节点有且只有一个子节点,且是右节点
        if (current == root) {
            root = current.rightChild;
        } else if (isLeftChild) {
            parent.leftChild = current.rightChild;
        } else {
            parent.rightChild = current.rightChild;
        }
    } else if (current.rightChild == null) {
        //该节点有且只有一个子节点,且是左节点
        if (current == root) {
            root = current.leftChild;
        } else if (isLeftChild) {
            parent.leftChild = current.leftChild;
        } else {
            parent.rightChild = current.leftChild;
        }
    } else {
        //该节点有两个节点
        Node successor = getSuccessor(current);
        if (successor == root) {
            root = null;
        } else if (isLeftChild) {
            parent.leftChild = successor;
        } else {
            parent.rightChild = successor;
        }
    }
    return true;
}

/**
 * 返回中序后继节点
 * @param delNode
 * @return
 */
private Node getSuccessor(Node delNode) {
    Node successor = delNode;
    Node successorParent = delNode;

    Node current = delNode.rightChild;
    while (current != null) {
        successorParent = successor;
        successor = current;
        current = current.leftChild;

    }

    if (delNode.rightChild != successor) {
        successorParent.leftChild = successor.rightChild;
        successor.rightChild = delNode.rightChild;
    }else{
        successor.leftChild=successorParent.leftChild;
    }
    return successor;
}

9、红黑树

红黑规则:

  • 每个节点不是红色就是黑色
  • 根总是黑色的
  • 如果节点是红色的,则它的子节点必须是黑色的
  • 从根节点到叶子节点的每条路径,必须包含相同数目的黑色节点

10、哈希表

分为两部分:key 和data

int类型key

info.java

package cn.xiaov.key_int;

public class Info {

    private int key;

    private String name;

    public int getKey() {
        return key;
    }

    public void setKey(int key) {
        this.key = key;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Info(int key, String name) {
        this.key = key;
        this.name = name;
    }
}

HashTable.java

package cn.xiaov.key_int;

public class HashTable {

    public Info[] arr;

    public HashTable(){
        arr =new Info[100];
    }

    /**
     * 指定初始化大小
     * @param value
     */
    public HashTable(int value){
        arr=new Info[value];
    }

    /**
     * 插入数据
     * @param info
     */
    public void insert(Info info){
        arr[info.getKey()]=info;
    }

    /**
     *  查找
     * @param key
     * @return
     */
    public Info find(int key){
        return arr[key];
    }

    /**
     * 删除数据
     * @param key
     */
    public void delete(int key){
        arr[key]=null;
    }

}
String类型key
开放地址法

底层是一个数组,压缩后如果冲突,hashValue++找寻相邻下一个数组值。

info.java

package cn.xiaov.key_string;

public class Info {
    private String key;

    private String name;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Info(String key, String name) {
        this.key = key;
        this.name = name;
    }
}

HashTable.java

package cn.xiaov.key_string;

import java.math.BigInteger;

/**
 * 开放地址法
 */
public class HashTable {

    public Info[] arr;

    public HashTable() {
        arr = new Info[100];
    }

    /**
     * 指定初始化大小
     *
     * @param value
     */
    public HashTable(int value) {

        arr = new Info[value];
    }

    /**
     * 插入数据
     *
     * @param info
     */
    public void insert(Info info) {
        //获取关键字
        String key = info.getKey();
        int hashValue = hashCode(key);
        while (arr[hashValue] != null && arr[hashValue].getName() != null) {
            hashValue++;
            hashValue %= arr.length;
        }
        arr[hashValue] = info;
    }

    /**
     * 查找
     *
     * @param key
     * @return
     */
    public Info find(String key) {
        int hashValue = hashCode(key);
        //连续区间
        while (arr[hashValue] != null) {
            if (arr[hashValue].getKey().equals(key)) {
                return arr[hashValue];
            }
            hashValue++;
            hashValue %= arr.length;
        }
        //没找到
        return null;
    }

    /**
     * 删除数据
     *
     * @param key
     */
    public boolean delete(String key) {
        Info info = find(key);
        if (info == null) {
            return false;
        } else {
            arr[hashCode(info.getKey())] = null;
            return true;
        }
    }

    /**
     * 将字母哈希化
     * @param key
     * @return
     */
    public int hashCode(String key) {
       /* int hashValue = 0;
        int pow27 = 1;
        for (int i = key.length() - 1; i >= 0; i--) {
            int letter;
            letter = key.charAt(i) - 96;
            hashValue += letter * pow27;
            pow27 *= 27;
        }*/
        BigInteger hashValue = new BigInteger("0");
        BigInteger pow27 = new BigInteger("1");
        for (int i = key.length() - 1; i >= 0; i--) {
            BigInteger letter = new BigInteger(String.valueOf(key.charAt(i) - 96));
            hashValue = hashValue.add(letter.multiply(pow27));
            pow27 = pow27.multiply(new BigInteger("27"));
        }
        return hashValue.mod(new BigInteger(String.valueOf(arr.length))).intValue();
    }

}
链地址法

底层是一个链表数组,压缩后如果冲突,直接链表添加,查找链表就好了。

info.java同上

Node.java

package cn.xiaov.chainaddress;

/**
 * 链结点
 */
public class Node {
    //数据域
    public Info info;
    //节点域 指向后一个节点   指针域
    public Node next;
    //指向前一个节点
    public Node previous;

    public Node(Info info){
        this.info=info;
    }

}

LinkList.java

package cn.xiaov.chainaddress;

/**
 * 单链表
 */
public class LinkList {
    //头节点
    private Node first;

    /**
     * 添加头节点
     *
     * @param info
     */
    public void insertFirst(Info info) {
        Node node = new Node(info);
        if (first == null) {
            first = node;
        } else {
            node.next = first;
            first = node;
        }
    }

    /**
     * 根据数据域删除一个节点,并返回该节点
     * 如果没有这个数据则返回null
     *
     * @param key
     * @return
     */
    public Node deleteNode(String key) {
        Node current = first;
        Node previous = first;
        //该节点为头节点
        if (key.equals(first.info.getKey())) {
            first = first.next;
            return current;
        }
        while (current != null) {
            if (key.equals(current.info.getKey())) {
                previous.next = current.next;
                return current;
            }
            previous = current;
            current = current.next;
        }
        return null;
    }

    /**
     * 根据数据域查找,如果有返回true
     *
     * @param key
     * @return
     */
    public Node find(String key) {
        Node current = first;
        while (current != null) {
            if (key.equals(current.info.getKey())) {
                return current;
            }
            current = current.next;
        }
        return null;
    }

    @Override
    public String toString() {
        Node current = first;
        String temp = "";
        while (current != null) {
            temp += current + " ";
            current = current.next;
        }
        return temp;
    }
}

HashTable.java

package cn.xiaov.chainaddress;

import java.math.BigInteger;

/**
 * 链地址法
 */
public class HashTable {

    public LinkList[] arr;

    public HashTable() {
        arr = new LinkList[100];
    }

    /**
     * 指定初始化大小
     *
     * @param value
     */
    public HashTable(int value) {

        arr = new LinkList[value];
    }

    /**
     * 插入数据
     *
     * @param info
     */
    public void insert(Info info) {
        //获取关键字
        String key = info.getKey();
        int hashValue = hashCode(key);

        if (arr[hashValue]==null){
            arr[hashValue]=new LinkList();
        }
        arr[hashValue].insertFirst(info);
    }

    /**
     * 查找
     *
     * @param key
     * @return
     */
    public Info find(String key) {
        int hashValue = hashCode(key);
        if (arr[hashValue]!=null) {
            return arr[hashValue].find(key).info;
        }else{
            return null;
        }
    }

    /**
     * 删除数据
     *
     * @param key
     */
    public boolean delete(String key) {
        Info info = find(key);
        if (info == null) {
            return false;
        } else {
            arr[hashCode(info.getKey())] = null;
            return true;
        }
    }

    /**
     * 将字母哈希化
     * @param key
     * @return
     */
    public int hashCode(String key) {
        BigInteger hashValue = new BigInteger("0");
        BigInteger pow27 = new BigInteger("1");
        for (int i = key.length() - 1; i >= 0; i--) {
            BigInteger letter = new BigInteger(String.valueOf(key.charAt(i) - 96));
            hashValue = hashValue.add(letter.multiply(pow27));
            pow27 = pow27.multiply(new BigInteger("27"));
        }
        return hashValue.mod(new BigInteger(String.valueOf(arr.length))).intValue();
    }
}

11、图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值