数组Array:
自己实现数组,依托的还是jdk底层的静态数组E[] data,数组的实际元素个数用size变量维护;
import java.util.ArrayList;
import java.util.Arrays;
public class Array<E> {
// private int[] data; // 现在只能承载int型数据
private E[] data; // 现在可以承载引用数据类型数据
private int size; // 用来描述我的数组中到底有多少个有效的数据
// 构造函数,传入数组的容量capacity构造Array
public Array(int capacity){
data = (E[])new Object[capacity];
size = 0;
}
// 无参构造,默认数组的容量capacity=10
public Array(){
this(10);
}
//获得数组中元素个数
public int getSize(){
return size;
}
//获得数组整体容量
public int getCapacity(){
return data.length;
}
//返回数组是否为空
public boolean isEmpty(){
return size == 0;
}
// 尾插 O(1)
public void addLast(E e){
// if (size == data.length){
// throw new IllegalArgumentException("数组已满");
// }
// // data[size++] = e;
// data[size] = e;
// size++;
add(size,e);
}
//头插 O(n)
public void addFirst(E e){
add(0,e);
}
// 向指定位置添加元素 O(n/2)=>O(n);忽略常数项
public void add(int index, E e){
// 对index合法性判断
if (index < 0 || index > size){
throw new IllegalArgumentException("index >= 0 and index <= size");
}
// 数组容量是否足够
if (size == data.length){
// throw new IllegalArgumentException("数组已满");
resize(2*data.length);
}
for (int i = size - 1; i >= index;i--){
data[i+1] = data[i];
}
data[index] = e;
size++;
}
// 获取index索引位置的元素O(1)
E get(int index){
if (index < 0 || index >= size){
throw new IllegalArgumentException("get failed index is illegal");
}
return data[index];
}
// 修改操作 O(1)
void set(int index, E e){
if (index < 0 || index >= size){
throw new IllegalArgumentException("get failed index is illegal");
}
data[index] = e;
}
// 查找数组中是否包含元素e
// O(n)
public boolean contains(E e){
for (int i = 0;i<size;i++){
if (data[i].equals(e)){
return true;
}
}
return false;
}
// 查找数组中元素e所在的索引,如果不存在元素e,则返回-1
// O(n)
public int find(E e){
for (int i = 0;i<size;i++){
if (data[i].equals(e)){
return i;
}
}
return -1;
}
//从数组中删除index位置的元素,返回删除的元素
public E remove(int index){
if (index < 0 || index >= size){
throw new IllegalArgumentException("get failed index is illegal");
}
E ret = data[index];
for (int i =index +1;i<size;i++)
data[i-1] = data[i];
size--;
data[size] = null; // 被垃圾回收掉 loitering objects
if (size == data.length / 4 && data.length / 2 != 0){
resize(data.length / 2);
}
return ret;
}
//从数组中删除第一个位置的元素,返回删除的元素
public E removeFirst(){
return remove(0);
}
//从数组中删除最后位置的元素,返回删除的元素
public E removeLast(){
return remove(size-1);
}
// 从数组中删除元素e
public void removeElement(E e){
int index = find(e);
if(index != -1)
remove(index);
}
@Override
public String toString() {
// return "Array{" +
// "data=" + Arrays.toString(data) +
// ", size=" + size +
// '}';
StringBuilder res = new StringBuilder();
res.append(String.format("Array: size = %d , capacity = %d\n",size,data.length));
res.append('[');
for (int i = 0; i<size;i++){
res.append(data[i]);
if (i != size -1){
res.append(", ");
}
}
res.append(']');
return res.toString();
}
private void resize(int newCapacity){
E[] newData = (E[])new Object[newCapacity];
for (int i = 0;i<size;i++)
newData[i] = data[i];
data = newData;
}
}
栈Stack:
先进后出FILSO,所有的操作时间复杂度都是O(1)
public interface Stack<E> {
/**
* 获得栈中元素个数
*/
int getSize();
/**
* 判断栈是否为空
*/
boolean isEmpty();
/**
*压栈操作,添加元素
*/
void push(E e);
/**
* 弹栈操作,取出元素
*/
E pop();
/**
* 看一下栈顶的元素
*/
E peek();
}
队列Queue:
队列和栈所定义的接口方法一致,玩法不一致的地方就是队列是先进先出FIFO,如果使用上面自定义的Array动态数组做队列实现,出队的操作是O(n)的复杂度,所以设计一个循环队列,队首元素出队之后,不需要移动元素,这时候队列的所有操作的时间复杂度也是O(1)。
public interface Queue<E> {
/**
* 得到队列的大小
*/
int getSize();
/**
* 判断队列是否为空
*/
boolean isEmpty();
/**
*添加元素
*/
void enqueue(E e);
/**
* 取出元素
*/
E dequeue();
/**
* 得到队列第一个元素
*/
E getFront();
}
循环队列的实现:
public class LoopQueue<E> implements Queue<E> {
private E[] data;
private int front,tail;
private int size;
public LoopQueue(int capacity){
// E[] data = (E[])new Object[capacity+1]; 如果这么写,该变量仅仅存在这个方法内,不会被赋为全局变量
data = (E[])new Object[capacity+1];
front = 0;
tail = 0;
size = 0;
}
public LoopQueue(){
this(10);
}
public int getCapacity(){
return data.length - 1;
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return front == tail;
}
@Override
public void enqueue(E e) {
if ((tail + 1) % data.length == front){
resize(getCapacity() * 2);
}
data[tail] = e;
tail = (tail + 1) % data.length;
size++;
}
private void resize(int newCapacity){
E[] newData = (E[])new Object[newCapacity +1];
for (int i = 0;i<size;i++){
newData[i] = data[(i+front)%data.length];
}
data = newData;
front = 0;
tail = size;
}
@Override
public E dequeue() {
if (isEmpty()){
throw new IllegalArgumentException("队列中没有元素可供删除");
}
E ret = data[front];
data[front] = null;
front = (front +1) % data.length;
size--;
if (size == getCapacity() / 4 && getCapacity() / 2 != 0)
resize(getCapacity() / 2);
return null;
}
@Override
public E getFront() {
if (isEmpty()){
throw new IllegalArgumentException("队列中没有元素可供删除");
}
return data[front];
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append(String.format("Queue: size = %d, capacity = %d\n",size,getCapacity()));
res.append("front [");
for (int i = front;i != tail ;i=(i+1) % data.length){
res.append(data[i]);
if ((i + 1) % data.length != tail)
res.append(", ");
}
res.append("] tail");
return res.toString();
}
public static void main(String[] args) {
LoopQueue<Integer> queue = new LoopQueue<>();
for (int i = 0;i<10;i++){
queue.enqueue(i);
System.out.println(queue);
if (i % 3 == 2){
queue.dequeue();
}
}
}
}
力扣上的list
public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
// 数组转链表(链表的构造函数)
public ListNode(int[] arr){
if (arr == null || arr.length == 0){
throw new IllegalArgumentException("arr cannot be empty");
}
this.val = arr[0];
ListNode cur = this;
for (int i = 1;i<arr.length;i++){
cur.next = new ListNode(arr[i]);
cur = cur.next;
}
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
ListNode cur = this;
while(cur != null){
res.append(cur.val + "->");
cur = cur.next;
}
res.append("NULL");
return res.toString();
}
}
链表LinkedList:
底层就是维护了一个内部类Node,Node有2个成员变量,一个存放数据的节点E e,还有个就是下一个节点的引用Node next(新new对象的引用,实际上就是这个对象在栈中的地址【指针】)
public class LinkedList<E> {
// java.util.LinkedList
private class Node{
public E e; // 元素
public Node next; // 指针 就是下一个元素的引用
public Node(E e,Node next){
this.e = e;
this.next = next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString(){
return e.toString();
}
}
// private Node head;
private Node dummyHead; // 虚拟头结点
private int size;
public LinkedList(){
dummyHead = new Node(null,null);
size = 0;
}
//链表中元素个数
public int getSize(){
return size;
}
// 返回链表是否为空
public boolean isEmpty(){
return size == 0;
}
//
// public void add(int index,E e){
// if(index < 0 || index > size)
// throw new IllegalArgumentException("索引越界");
// if (index == 0)
// addFirst(e);
// else {
// Node prev = head;
// for (int i = 0;i<index;i++)
// prev = prev.next;
//
// prev.next = new Node(e, prev.next);
// size++;
// }
// }
public void add(int index,E e){
if(index < 0 || index > size)
throw new IllegalArgumentException("索引越界");
Node prev = dummyHead;
for (int i = 0;i<index;i++)
prev = prev.next;
prev.next = new Node(e, prev.next);
size++;
}
// 头添加
public void addFirst(E e){
// Node node = new Node(e);
// node.next = head;
// head = node;
// head = new Node(e, head);
// size++;
add(0,e);
}
// 尾添加
public void addLast(E e){
add(size,e);
}
// 获得
public E get(int index){
if(index < 0 || index > size)
throw new IllegalArgumentException("索引越界");
Node cur = dummyHead.next;
for (int i = 0;i<index;i++)
cur = cur.next;
return cur.e;
}
public E getFirst(){
return get(0);
}
public E getLast(){
return get(size - 1);
}
public void set(int index, E e){
if(index < 0 || index > size)
throw new IllegalArgumentException("索引越界");
Node cur = dummyHead.next;
for (int i=0;i<index;i++)
cur = cur.next;
cur.e = e;
}
// 是否包含
public boolean contains(E e){
Node cur = dummyHead.next;
while(cur != null){
if (cur.e.equals(e))
return true;
cur = cur.next;
}
return false;
}
// 删除元素
public E remove(int index){
if(index < 0 || index >= size)
throw new IllegalArgumentException("索引越界");
Node prev = this.dummyHead;
for (int i=0;i<index;i++)
prev = prev.next;
Node retNode = prev.next;
prev.next = retNode.next;
retNode.next = null;
size--;
return retNode.e;
}
public E removeFirst(){
return remove(0);
}
public E removeLast(){
return remove(size - 1);
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
// Node cur = dummyHead.next;
// while(cur != null){
// res.append(cur + "->");
// cur = cur.next;
// }
for (Node cur = dummyHead.next;cur != null;cur = cur.next)
res.append(cur + "->");
res.append("NULL");
return res.toString();
}
}