顺序存储结构
数组:一组连续的数,以下标为索引,在内存中是连续的
import java.util.Arrays;
/**
* 面向对象的数组
* 扩展:集合的底层实现原理
*/
public class Demo {
private int[] elements;
public Demo() {
elements = new int[0];
}
/**
* 获取数组的长度
*
* @return
*/
public int size() {
return elements.length;
}
/**
* 往数组中添加一个元素
*
* @param val
*/
public void add(int val) {
int[] newArray = new int[elements.length + 1];
for (int i = 0; i < elements.length; i++) {
newArray[i] = elements[i];
}
newArray[newArray.length - 1] = val;
elements = newArray;
}
/**
* 删除某个元素
*
* @param index 删除元素的下标,从0开始
*/
public void remove(int index) {
if (index < 0 || index > elements.length - 1) {
throw new RuntimeException("数组下标越界");
}
int[] newArray = new int[elements.length - 1];
for (int i = 0; i < newArray.length; i++) {
if (i < index) {
newArray[i] = elements[i];
} else {
newArray[i] = elements[i + 1];
}
}
elements = newArray;
}
/**
* 向指定位置插入一个元素
*
* @param val 插入的值
* @param index 插入的位置 从0开始
*/
public void insert(int val, int index) {
if (index < 0 || index > elements.length - 1) {
throw new RuntimeException("数组下标越界");
}
int[] newArray = new int[elements.length + 1];
for (int i = 0; i < newArray.length; i++) {
if (i < index) {
newArray[i] = elements[i];
} else if (i == index) {
newArray[i] = val;
} else {
newArray[i] = elements[i - 1];
}
}
elements = newArray;
}
/**
* 打印数组
*/
public void print() {
System.out.println(Arrays.toString(elements));
}
}
栈:一组连续的数,区分于数组的点在于其数据遵循先进后出的原则
public class Demo {
private int[] elements;
public Demo() {
elements = new int[0];
}
/**
* 压入一个数据
*
* @param val
*/
public void push(int val) {
int[] array = new int[elements.length + 1];
for (int i = 0; i < elements.length; i++) {
array[i] = elements[i];
}
array[array.length - 1] = val;
elements = array;
}
/**
* 取出栈顶元素
*/
public int pop() {
if (elements.length == 0) {
throw new RuntimeException("stack is empty");
}
int[] array = new int[elements.length - 1];
for (int i = 0; i < array.length; i++) {
array[i] = elements[i];
}
int result = elements[elements.length - 1];
elements = array;
return result;
}
/**
* 查看栈顶元素
*
* @return
*/
public int peek() {
if (elements.length == 0) {
throw new RuntimeException("stack is empty");
}
return elements[elements.length - 1];
}
}
队列:一组连续的数,其特点是先进先出
/**
* 队列
*
* 其特点是先进先出
*/
public class Queue {
private int[] elements;
public Queue() {
elements = new int[0];
}
/**
* 入队
*
* @param val
*/
public void add(int val) {
int[] array = new int[elements.length + 1];
for (int i = 0; i < elements.length; i++) {
array[i] = elements[i];
}
array[array.length - 1] = val;
elements = array;
}
/**
* 出队
*
* @return
*/
public int poll() {
if (elements.length <= 0) {
throw new RuntimeException("queue is empty");
}
int element = elements[0];
int[] array = new int[elements.length - 1];
for (int i = 0; i < array.length; i++) {
array[i] = elements[i + 1];
}
elements = array;
return element;
}
}
链式存储结构
单链表:每一节点分成两部分,一部分存储本身的值另一部分存储下一个节点的地址
/**
* 单链表
* 链式存储结构,每一节点分成两部分,一部分存储本身的值另一部分存储下一个节点的地址
* 扩展知识点:
* 对于Java来说,所谓的地址其实就是对象本身,基本类型存储的是值,引用类型存储的都是地址
* ,所以当前类的属性next是一个对象,但是我们说成存储的是下一个对象的地址
*/
public class Node {
private int data;
private Node next;//下一个对象的地址
public Node(int data) {
this.data = data;
}
/**
* 追加节点,
*/
public Node append(Node next) {
Node current = this;
//如果当前节点有下一节点就一直循环,直到找到最后一个节点
while (current.hasNext()) {
current = current.next;
}
current.next = next;
return current;
}
/**
* 删除下一个节点,单链表只能删除下一个节点
*/
public void removeNext() {
//取出下下个节点
Node node = next.next;
//将下下个节点赋值给当前节点的下一个节点
next = node;
}
/**
* 插入一个节点,单链表只能往后插入一个新节点
*/
public void insert(Node node){
//下一节点作为当前节点的下一节点
node.next = next;
//要插入的节点作为当前节点的下一个节点
this.next = node;
}
/**
* 获取下一个节点
*/
public Node next() {
return next;
}
/**
* 获取节点中的数据
*/
public int getData() {
return this.data;
}
/**
* 判断当前节点是否是最后一个节点
*/
public boolean hasNext() {
return next != null;
}
/**
* 打印所有节点
*
* @return
*/
public void show() {
Node current = this;
while (current.hasNext()) {
System.out.print(current.data + ",");
current = current.next;
}
System.out.println(current.getData());
}
}
循环单链表:和单链表唯一的区别就是最后一个节点指向第一个节点,所有数据形成一个闭环,不存在第一个节点和最后一个节点
/**
* 循环链表
* <p>
* 和单链表唯一的区别就是最后一个节点指向第一个节点
*/
public class LoopNode {
private int data;
private LoopNode next = this;
public LoopNode(int data) {
this.data = data;
}
/**
* 删除下一个节点
*/
public void removeNext() {
//取出下下个节点
LoopNode node = next.next;
//将下下个节点赋值给当前节点的下一个节点
next = node;
}
/**
* 插入一个节点
*/
public void insert(LoopNode node) {
//下一节点作为当前节点的下一节点
node.next = next;
//要插入的节点作为当前节点的下一个节点
this.next = node;
}
/**
* 获取下一个节点
*/
public LoopNode next() {
return next;
}
/**
* 获取节点中的数据
*/
public int getData() {
return this.data;
}
}
双链表:在单链表的基础上增加一部分用来存储上一个节点的地址
/**
* 双向链表
* 在单链表的基础上再增加一部分用来存储上一个节点的地址
*
* 当前类展示的是双向循环链表
*/
public class DoubleNode {
private DoubleNode previous = this;
private int data;
private DoubleNode next = this;
public DoubleNode(int data){
this.data = data;
}
/**
* 插入一个节点
*/
public void insert(DoubleNode doubleNode){
//当前节点的下一个节点的前一个节点为要插入的节点
next.previous = doubleNode;
//要插入的节点的下一个节点为当前节点的下一个节点
doubleNode.next = next;
//要插入节点的前一个节点为当前节点
doubleNode.previous = this;
//当前节点的下一个节点为要插入的节点
this.next = doubleNode;
}
/**
* 获取下一个节点
*/
public DoubleNode next() {
return next;
}
/**
* 获取上一个节点
*/
public DoubleNode previous(){
return previous;
}
/**
* 获取值
*/
public int getData() {
return data;
}
}
综上就是数据存储的两种基本结构,顺序存储查询更快,链式存储增删更快。