Java版数据结构与算法

  由于之前老师教的数据结构与算法是C语言版本,并且自己学的并不是很扎实,考虑到以后自己毕竟要靠Java吃饭,于是乎就在暑期安排一波,以Java面向对象的思想重学一遍数据结构与算法。网上很多人说看JDK源码就可以,可能是我比较笨吧,还是喜欢自己手过一遍,彻底弄明白Java中的数据结构与算法。
  少啰嗦,上代码!

文章目录

  • 一、表、栈和队列
      • 1.1 ArrayList
      • 1.2 LinkedList
      • 1.3 栈*
      • 1.4 队列*
  • 二、树

一、表、栈和队列

1.1 ArrayList

import java.util.Iterator;

/**
 * 仿写Java.util中的ArrayList数据结构
 *
 * 1.0版本
 * 修改日期:2020.7.22
 */

public class MyArrayList<AnyType> implements Iterable<AnyType> {
    private static final int DEFAULT_CAPACITY = 10;

    private int length;
    private AnyType[] items;

    public MyArrayList() {
        doClear();
    }

    public void clear() {
        doClear();
    }

    private void doClear() {//私有初始化方法
        length = 0;
        ensureCapacity(DEFAULT_CAPACITY);
    }

    public int size() {
        return length;
    }

    public boolean isEmpty() {
        return size() == 0;
    }

    public void trimToSize() {
        ensureCapacity(size());
    }

    public AnyType get(int index) {
        if (index < 0 || index >= size())
            throw new ArrayIndexOutOfBoundsException();

        return items[index];
    }

    public AnyType set(int index, AnyType newVal) {
        if (index < 0 || index >= size())
            throw new ArrayIndexOutOfBoundsException();

        AnyType item = items[index];
        items[index] = newVal;
        return item;
    }

    public void ensureCapacity(int newCapacity) {
        if (newCapacity < length) {
            return;
        }

        AnyType[] old = items;
        //新建一个Object数组引用并将其强制转换为AnyType类型
        items = (AnyType[]) new Object[newCapacity];
        for (int i = 0; i < size(); ++i)
            items[i] = old[i];
    }

    public boolean add(AnyType x) {
        add(size(), x);//实现在尾部添加新元素
        return true;
    }

    public void add(int index, AnyType x) {
        if (items.length == size())
            ensureCapacity(size() * 2 + 1);

        for (int i = length; i < size() - 1; ++i)
            items[i] = items[i - 1];
        items[index] = x;

        length++;
    }

    public AnyType remove(int index) {
        if (index < 0 || index >= size())
            throw new ArrayIndexOutOfBoundsException();

        AnyType removedItem = items[index];
        for (int i = index; i < size() - 1; i++)
            items[i] = items[i + 1];

        length--;
        return removedItem;
    }

    public Iterator<AnyType> iterator() {
        return new ArrayListIterator();
    }

    //实现迭代器ArrayListIterator内部类
    private class ArrayListIterator implements Iterator<AnyType> {
        private int current = 0;

        public boolean hasNext() {
            return current < size();
        }

        public AnyType next() {
            if (!hasNext())
                throw new java.util.NoSuchElementException();
            return items[current++];
        }

        public void remove() {
            MyArrayList.this.remove(--current);
        }
    }

    //测试MyArrayList:
    public static void main(String[] args) {
        MyArrayList<String> basicCourses = new MyArrayList<>();
        basicCourses.add("计算机组成原理");
        basicCourses.add("数据结构与算法");
        basicCourses.add("计算机操作系统");
        basicCourses.add("计算机网络");
        basicCourses.add("软件体系结构");
        basicCourses.add("软件工程导论");
        System.out.println("共记" + basicCourses.size() + "门软件工程基础课");
        System.out.println(basicCourses.remove(0) + "已经学完");
        System.out.println(basicCourses.remove(0) + "已经学完");
        System.out.println("目前还有" + basicCourses.size() + "门基础课程没学,分别是:");
        Iterator iter = basicCourses.iterator();
        while (iter.hasNext()){
            System.out.println("\t" + iter.next());
        }
    }
}

测试结果:
Java版数据结构与算法_第1张图片

可以看出,ArrayList是使用对象数组实现的。

get() 直接读取第几个下标,复杂度 O(1)
add(E) 添加元素,直接在后面添加,复杂度O(1)
add(index, E) 添加元素,在第几个元素后面插入,后面的元素需要向后移动,复杂度O(n)
remove()删除元素,后面的元素需要逐个移动,复杂度O(n)

显然,ArrayList更适合经常访问或修改元素内容的应用场景,而不适合频繁使用增加和删除操作的应用场景。

1.2 LinkedList

/**
 * 仿写Java.util中的LinkedList数据结构
 *
 * 1.0版本
 * 修改日期:2020.7.22
 */

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class MyLinkedList<AnyType> implements Iterable<AnyType> {
    private static class Node<AnyType> {//内部结点类
        private AnyType data;
        private Node<AnyType> prev;//前驱结点
        private Node<AnyType> next;//后继结点

        public Node(AnyType data, Node<AnyType> prev, Node<AnyType> next) {
            this.data = data;
            this.prev = prev;
            this.next = next;
        }
    }

    //成员属性
    private int size;
    private int modCount = 0;
    private Node<AnyType> beginMarker;
    private Node<AnyType> endMarker;

    //私有成员方法
    private void doClear() {//私有初始化方法
        beginMarker = new Node<AnyType>(null, null, null);
        endMarker = new Node<AnyType>(null, null, null);
        beginMarker.next = endMarker;
        endMarker.prev = beginMarker;

        size = 0;
        modCount++;
    }
    
    private Node<AnyType> getNode(int index) {//私有找结点方法
        return getNode(index, 0, size() - 1);
    }
    
    private Node<AnyType> getNode(int index, int lower, int upper) {//私有找结点方法的实现
        Node<AnyType> p;

        if (index < lower || index > upper) {
            throw new IndexOutOfBoundsException();
        }

        if (index < size() / 2) {//如果要找的结点位于链表前半段则从前往后找
            p = beginMarker.next;
            for (int i = 0; i < index; ++i)
                p = p.next;
        } else {//如果要找的结点位于链表后半段则从后往前找
            p = endMarker;
            for (int i = size(); i > index; --i)
                p = p.prev;
        }

        return p;
    }

    private void addBefore(Node<AnyType> p, AnyType x) {//私有结点插入方法
        Node<AnyType> newNode = new Node<>(x, p.prev, p);
        newNode.prev.next = newNode;//令前驱结点的后继结点为当前插入的结点
        p.prev = newNode;//令后继结点的前驱结点为当前插入的结点
        size++;
        modCount++;
    }

    private AnyType remove(Node<AnyType> p) {//私有结点删除方法
        p.next.prev = p.prev;
        p.prev.next = p.next;
        size--;
        modCount++;

        return p.data;
    }
    
    public MyLinkedList() {
        doClear();
    }

    public void clear() {
        doClear();
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size() == 0;
    }
    
    public boolean add(AnyType x) {
        add(size(), x);
        return true;
    }

    public void add(int index, AnyType x) {
        addBefore(getNode(index, 0, size()), x);
    }

    public AnyType get(int index) {
        return getNode(index).data;
    }

    public AnyType set(int index, AnyType newVal) {
        Node<AnyType> p = getNode(index);
        AnyType oldVal = p.data;
        p.data = newVal;
        return oldVal;
    }

    public AnyType remove(int index) {
        return remove(getNode(index));
    }

    public Iterator<AnyType> iterator() {
        return new LinkedListIterator();
    }

    private class LinkedListIterator implements Iterator<AnyType> {//内部迭代器类
        private Node<AnyType> current = beginMarker.next;
        private int expectedModCurrent = modCount;
        private boolean okToRemove = false;

        public boolean hasNext() {
            return current != endMarker;
        }

        public AnyType next() {
            if (modCount != expectedModCurrent)
                throw new ConcurrentModificationException();
            if (!hasNext()) {
                throw new NoSuchElementException();
            }

            AnyType nextItem = current.data;
            current = current.next;
            okToRemove = true;
            return nextItem;
        }

        public void remove() {
            if (modCount != expectedModCurrent)
                throw new ConcurrentModificationException();
            if (!okToRemove)
                throw new IllegalStateException();

            MyLinkedList.this.remove(current.prev);
            expectedModCurrent++;
            okToRemove = false;
        }
    }

    //测试MyLinkedList:
    public static void main(String[] args) {
        MyLinkedList<String> basicCourses = new MyLinkedList<>();
        basicCourses.add("计算机组成原理");
        basicCourses.add("数据结构与算法");
        basicCourses.add("计算机操作系统");
        basicCourses.add("计算机网络");
        basicCourses.add("软件体系结构");
        basicCourses.add("软件工程导论");
        System.out.println("共记" + basicCourses.size() + "门软件工程基础课");
        System.out.println(basicCourses.remove(0) + "已经学完");
        System.out.println(basicCourses.remove(0) + "已经学完");
        System.out.println("目前还有" + basicCourses.size() + "门基础课程没学,分别是:");
        Iterator iter = basicCourses.iterator();
        while (iter.hasNext()) {
            System.out.println("\t" + iter.next());
        }
    }
}

测试结果:
Java版数据结构与算法_第2张图片

可以看出,LinkedList是使用双向链表实现的。

get() 获取第几个元素,依次遍历,复杂度O(n)
add(E) 添加到末尾,复杂度O(1)
add(index, E) 添加第几个元素后,需要先查找到第几个元素,直接指针指向操作,复杂度O(n)
remove()删除元素,直接指针指向操作,复杂度O(1)

显然,LinkedList更适合频繁使用增加和删除操作的应用场景,而不适合经常访问或修改元素内容的应用场景。

1.3 栈*

栈又称后进先出(LIFO)表。栈的基本操作有pop()出栈和push()入栈,前者相当于在栈顶插入元素,后者相当于删除栈顶元素。可以通过top()方法查看栈顶元素。需要注意的是,栈中的元素只有栈顶元素是可以访问的。

  • 栈的实现
    • ArrayList实现(较小规模适用)
    • LinkedList实现(较大规模适用)
  • 栈的应用
    • 平衡符号:用于编译器检查语法错误,比如少一两个符号导致的错误。
      算法做一个空栈。读取字符直到文件结尾。如果字符是一个开放符号,则将其推入栈中。如果租房是一个封闭符号,则当栈空时报错,否则将栈顶元素弹出。如果弹出的不是对应的开放符号则报错。在文件结尾处,若栈非空则报错。
    • 计算后缀表达式
    • 中缀到后缀的转换
    • 方法调用

1.4 队列*

队列又称先进先出(FIFO)表。队列的基本操作有enqueue()入队和dequeue()出队,前者相当于在队尾插入元素,后缀相当于在队首删除元素。可以通过front()方法来查看队首元素。同样需要注意的是,队列中的元素只有队首元素是可以访问的。

  • 队列的实现
    • 使用LinkedList实现(最简单最高效)
    • 使用循环数组实现
  • 队列的应用
    • 消息队列
    • 邮件队列
    • 进程队列

二、树

持续更新中……
打*的章节我自己也不甚理解。怕大家误会,后续会继续补充,特此说明~~

你可能感兴趣的:(Java)