日常学习算法总结

一、基本数据结构之数组
自定义数组(类似ArrayList),数组必须存在在连续的地址空间,实现数组的增删操作。

public class CustomArray {
    private int[] array;
    // 元素个数
    private int size;
    private static final String TAG = "CustomArray";

    public CustomArray(int capacity) {
        array = new int[capacity];
        size = 0;
    }

    public void insert(int index, int element) {
        // 判断下标是否合法
        if (index < 0 || index > size) {
            throw new ArrayIndexOutOfBoundsException("数组越界,超出已有元素范围");
        }
        // 如果实际元素个数达到数组容量的上限,则进行扩容
        if (size >= array.length) {
            LogUtils.d(TAG, "我扩容了");
            expansionArray();
        }
        // 数组在内存中占有连续的内存空间,数组插入一个元素,插入位置后面的元素需要依次像后移动一位
        /*for (int i = size - 1; i >= index; i--) {
            array[i + 1] = array[i];
        }*/
        if (size - 1 - index >= 0) System.arraycopy(array, index, array, index + 1, size - 1 - index);
        array[index] = element;
        size++;
    }

    public int delete(int index) {
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("数组越界,超出已有元素范围");
        }
        int delElement = array[index];
        // 需要将元素向前移动一位
        /*for (int i = index; i < size - 1; i++) {
            array[i] = array[i + 1];
        }*/
        // 下面这种方式其实是牺牲空间复杂度来提升时间复杂度
        if (size - 1 - index >= 0) System.arraycopy(array, index + 1, array, index, size - 1 - index);
        size--;
        return delElement;
    }

    public int get(int index) {
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("数组越界,超出已有元素范围");
        }
        return array[index];
    }

    public void set(int index, int element) {
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("数组越界,超出已有元素范围");
        }
        array[index] = element;
    }

    private void expansionArray() {
        // 进行两倍扩容
        int[] newArray = new int[array.length * 2];
        System.arraycopy(array, 0, newArray, 0, array.length);
        array = newArray;
    }

    public void outArray() {
        if (array == null) {
            return;
        }
        for (int element : array) {
            LogUtils.d(TAG, "数组元素:" + element);
        }
    }

    public int[] getArray() {
        return array;
    }

    public int getSize() {
        return size;
    }
}

二、基本数据结构之链表
自定义链表(类似LinkedList),实现增删操作

2.1、定义节点类

public class Node {
    public int data;
    public Node next;

    public Node() {
    }

    public Node(int data) {
        this.data = data;
    }
}

2.2、实现链表

public class CustomLinkedList {
    // 头结点指针
    private Node head;
    // 尾节点指针
    private Node last;
    // 链表长度
    private int size;

    public void insert(int index, int element) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("链表越界,超出链表实际范围");
        }
        Node insertNode = new Node(element);
        if (size == 0) {
            // 链表长度为0,空链表
            head = insertNode;
            last = insertNode;
        } else if (index == 0) {
            // 插入头部
            insertNode.next = head;
            head = insertNode;
        } else if (index == size) {
            // 插入尾部
            last.next = insertNode;
            last = insertNode;
        } else {
            // 插入中间
            // 获取前一个节点
            Node preNode = get(index - 1);
            Node nextNode = preNode.next;
            preNode.next = insertNode;
            insertNode.next = nextNode;
        }
        size++;
    }

    public Node remove(int index) {
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("链表越界,超出链表实际范围");
        }
        Node removeNode = null;
        if (index == 0) {
            // 删除头部
            removeNode = head;
            head = head.next;
        } else if (index == size - 1) {
            // 删除尾节点
            Node preNode = get(index - 1);
            removeNode = preNode.next;
            preNode.next = null;
            last = preNode;
        } else {
            // 删除中间节点
            Node preNode = get(index - 1);
            Node nextNode = preNode.next.next;
            removeNode = preNode.next;
            preNode.next = nextNode;
        }
        size--;
        return removeNode;
    }

    /**
     * 查询
     *
     * @param index
     * @return
     */
    public Node get(int index) {
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("链表越界,超出链表实际范围");
        }
        Node tempNode = head;
        for (int i = 0; i < index; i++) {
            tempNode = tempNode.next;
        }
        return tempNode;
    }

    public String outPut() {
        StringBuilder builder = new StringBuilder();
        Node tempNode = head;
        while (tempNode != null) {
            builder.append(tempNode.data).append(" ");
            tempNode = tempNode.next;
        }
        return builder.toString();
    }

    public Node getNode() {
        return head;
    }

    public String outNode(Node node) {
        StringBuilder builder = new StringBuilder();
        Node tempNode = node;
        while (tempNode != null) {
            builder.append(tempNode.data).append(" ");
            tempNode = tempNode.next;
        }
        return builder.toString();
    }
}

三、反转链表

刚好利用上诉我们自定义的链表实现链表反转

/**
     * 反转链表
     * @param node
     * @return
     */
    public Node reverseLinkedList(Node node) {
        // 当前节点,将传递进来的头结点赋值给当前节点
        Node curNode = node;
        // 下一个节点
        Node nextNode;
        // 前一个节点
        Node preNode = null;
        while (curNode != null) {
            // 取出当前节点的下一个节点赋值给我们定义好的nextNode
            nextNode = curNode.next;
            // 将当前节点指向前一个节点实现反转
            curNode.next = preNode;
            // 将当前节点赋值给前一节点
            preNode = curNode;
            // 移动当前节点到下一个节点
            curNode = nextNode;
        }
        return preNode;
    }

调用:

val cusLinkedList = CustomLinkedList()
cusLinkedList.insert(0, 0)
cusLinkedList.insert(1, 1)
cusLinkedList.insert(2, 2)
cusLinkedList.insert(3, 3)
cusLinkedList.insert(4, 4)
cusLinkedList.insert(5, 5)
cusLinkedList.insert(6, 6)
cusLinkedList.insert(7, 7)
cusLinkedList.insert(8, 8)

val node = reverseLinkedList(cusLinkedList.node)
val nodeStr = cusLinkedList.outNode(node)
LogUtils.d(TAG, "反转链表: $nodeStr")

结果:

TestAlgorithmFragment==>: 反转链表: 8 7 6 5 4 3 2 1 0 

四、获取数组中出现次数最多的元素

4.1、双层for循环

/**
     * 获取数组中出现最多的元素和次数
     *
     * @param arr
     * @return
     */
    public int getArrayMostFrequent(int[] arr) {
        int mostElement = 0;
        int tempCount = 0;
        int timeCount = 0;
        for (int i = 0; i < arr.length; i++) {
            tempCount = 0;
            for (int j = 0; j < arr.length; j++) {
                if (arr[i] == arr[j]) {
                    tempCount++;
                }
            }
            if (tempCount > timeCount) {
                timeCount = tempCount;
                mostElement = arr[i];
            }
        }
        LogUtils.d(TAG, "出现次数最多的元素: " + mostElement + "==>次数: " + timeCount);
        return timeCount;
    }

4.2、利用map集合,将当前元素作为key,出现次数作为value,然后遍历map集合,value值最大的元素就是出现次数最多的元素

/**
     * 获取数组中出现最多的元素和次数
     * 使用map优化
     *
     * @param arr
     * @return
     */
    public int getArrayMostFrequentForMap(int[] arr) {
        Map<Integer, Integer> map = new HashMap<>();

        int mostElement = 0;
        int count = 0;
        int timeCount = 0;
        for (int i = 0; i < arr.length; i++) {
            if (map.containsKey(arr[i])) {
                map.put(arr[i], map.get(arr[i]) + 1);
            } else {
                map.put(arr[i], 1);
            }
        }
        for (Integer key : map.keySet()) {
            if (map.get(key) > timeCount) {
                timeCount = map.get(key);
                mostElement = key;
            }
            count++;
        }
        LogUtils.d(TAG + "使用Map优化", "出现次数最多的元素: " + mostElement + "==>最多元素次数: " + timeCount
                + "元素合并之后遍历次数: " + count);
        return timeCount;
    }

你可能感兴趣的:(算法,算法,链表,数据结构,java)