数据结构概述
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。
数据结构分类
物理结构
数组:数组用来存放相同类型的数据,数组在计算机中内存的开辟是连续的,而且数组一旦被定义,它的大小是不能再改变了,除非重新开辟一个更大的数组。
链表:与数组不同,链表在计算机中内存的开辟是跳跃的,它有一个指向后继的引用(双向链表还有一个指向前驱的引用),所以只要能够获取链表的头,那么剩下的数据就能轻松获取了。
数组和链表的相同与不同:
1.数组和链表都是计算机内存中真实存在的数据组织方式,所以称为物理结构。
2.数组和链表在逻辑上都可以成环,数组成环依靠下标+1模数组长度,让下标每到达数组长度-1时变为0,链表依靠循环链表。
3.数组由于有索引存在,所以便于读操作,但是不适合增删操作,因为要保持有序,必须把元素移位,这很耗时。链表由于有指向下一个元素的引用存在,所以适合增删操作,只需要更改引用,但是不适合读操作,因为无法快速定位到需要读的元素。
逻辑结构
逻辑结构分为线性表和非线性表,简单数据结构先介绍线性表,非线性表之后再述。
线性表
栈:栈是只能在一端加入元素和删除元素,加入元素称为入栈,删除元素称为出栈,最先入栈的元素被压入栈底,最后入栈的元素在栈顶,所以最先入栈的元素最后出栈,所以栈是先进后出。
队列:队列可以在一端加入元素,另一端删除元素,加入元素称为入队,删除元素称为出队,最先入队的元素在队头,最后入队的元素在队尾,所以最先入队的元素最先出队,所以队列是先进先出。
栈和队列都可以使用数组和链表实现。
非线性表
栈和队列的实现
数组实现一个栈
public class OrderStack<E> {
//指向栈顶的引用
private int top;
//数组 存放元素
private E[] stackArrays;
public OrderStack() {
this(5);
}
@SuppressWarnings("unchecked")
private OrderStack(int capacity) {
this.top = 0;//栈顶 从0开始
this.stackArrays = (E[]) new Object[capacity];
}
public boolean isFull() {
return top == stackArrays.length;
}
//入栈
public void push(E val) {
//判满
if (isFull()) {
stackArrays = Arrays.copyOf(stackArrays, stackArrays.length * 2);
}
stackArrays[top++] = val;
}
public boolean isEmpty() {
return top == 0;
}
//出栈 返回栈顶元素并且删除
public E pop() {
//判空
if (isEmpty()) {
throw new UnsupportedOperationException("the stack is empty");
}
E result = stackArrays[top - 1];
stackArrays[top - 1] = null;
top--;
return result;
}
//获取栈顶元素
public E peek() {
//判空
if (isEmpty()) {
throw new UnsupportedOperationException("the stack is empty");
}
return stackArrays[top - 1];
}
}
链表实现一个栈
public class LinkedListStack<E>{
private Node<E> top;
class Node<E>{
protected E data;
protected Node<E> next;
Node(E data){
this.data = data;
this.next = null;
}
}
@SuppressWarnings("unchecked")
public LinkedListStack(){
top = new Node<E>((E)new Object());//头引用,位于栈底
}
//入栈 头插
public void push(E val){
//创建一个新节点
Node<E> newNode = new Node<>(val);
newNode.next = top.next;
top.next = newNode;
}
//出栈 获取栈顶元素并删除
public E pop(){
if(top.next == null) return null;
E result = top.next.data;
top.next = top.next.next;
return result;
}
//获取栈顶元素
public E peek(){
if(top.next == null) return null;
return top.next.data;
}
}
数组实现一个队列
public class ArrayQueue<E>{
private int front;//队头 删除元素
private int rear;//队尾 添加元素
private E[] elements;
private static int defaultSize = 5;
public ArrayQueue(){
this(defaultSize);
}
@SuppressWarnings("unchecked")
public ArrayQueue(int size){
elements = (E[])new Object[size];
front = 0;
rear = 0;
}
//判空
public boolean isEmpty(){
return front == rear;
}
//判满
public boolean isFull(){
return rear == elements.length;
}
//入队
public void push(E value){
if(isFull()){
elements = Arrays.copyOf(elements,elements.length<<1);
}
elements[rear++] = value;
}
//出队
public E pop(){
if(isEmpty()){
return null;
}
E tmp = elements[front];
System.arraycopy(elements, 1, elements, 0, rear - front);
rear--;
return tmp;
}
}
链表实现一个队列
public class LinkedListQueue<E> {
private Node<E> front; //队头 删除元素
private Node<E> rear;//队尾 添加元素
class Node<E> {
protected E data;
protected Node<E> next;
public Node(E data) {
this.data = data;
}
}
//判空
public boolean isEmpty() {
return front == null && rear == null;
}
public void push(E data) {
Node<E> newNode = new Node<>(data);
//rear 队尾 入队
if (isEmpty()) {
front = newNode;
rear = front;
} else {
rear.next = newNode;
rear = rear.next;
}
}
public Node<E> pop() {
if (isEmpty()) {
return null;
}
//front 队头 出队
Node<E> cur = front;
front = front.next;
return cur;
}
}