由于之前老师教的数据结构与算法是C语言版本,并且自己学的并不是很扎实,考虑到以后自己毕竟要靠Java吃饭,于是乎就在暑期安排一波,以Java面向对象的思想重学一遍数据结构与算法。网上很多人说看JDK源码就可以,可能是我比较笨吧,还是喜欢自己手过一遍,彻底弄明白Java中的数据结构与算法。
少啰嗦,上代码!
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());
}
}
}
可以看出,ArrayList是使用对象数组实现的。
get() 直接读取第几个下标,复杂度 O(1)
add(E) 添加元素,直接在后面添加,复杂度O(1)
add(index, E) 添加元素,在第几个元素后面插入,后面的元素需要向后移动,复杂度O(n)
remove()删除元素,后面的元素需要逐个移动,复杂度O(n)
显然,ArrayList更适合经常访问或修改元素内容的应用场景,而不适合频繁使用增加和删除操作的应用场景。
/**
* 仿写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());
}
}
}
可以看出,LinkedList是使用双向链表实现的。
get() 获取第几个元素,依次遍历,复杂度O(n)
add(E) 添加到末尾,复杂度O(1)
add(index, E) 添加第几个元素后,需要先查找到第几个元素,直接指针指向操作,复杂度O(n)
remove()删除元素,直接指针指向操作,复杂度O(1)
显然,LinkedList更适合频繁使用增加和删除操作的应用场景,而不适合经常访问或修改元素内容的应用场景。
栈又称后进先出(LIFO)表。栈的基本操作有pop()出栈和push()入栈,前者相当于在栈顶插入元素,后者相当于删除栈顶元素。可以通过top()方法查看栈顶元素。需要注意的是,栈中的元素只有栈顶元素是可以访问的。
队列又称先进先出(FIFO)表。队列的基本操作有enqueue()入队和dequeue()出队,前者相当于在队尾插入元素,后缀相当于在队首删除元素。可以通过front()方法来查看队首元素。同样需要注意的是,队列中的元素只有队首元素是可以访问的。
持续更新中……
打*的章节我自己也不甚理解。怕大家误会,后续会继续补充,特此说明~~