文章目录
一、线性结构
1.1顺序存储(开辟一组连续的空间存储数据)
1.1.1线性表
1. Java内置数组的优点
① 数组一旦创建不能改变
int[] arr1 = new int [5]; //创建5个默认值为0的数组
int[] arr2 = new int[]{1,2,3,4,5}; //创建五个赋初始值的数组
②数组只能存储同一类型的数据
double[] arr3 = new double[5]; //可以存储全int或者全double类型的数据,向下兼容
③数组中每个存储空间地址连续且相等
如果要插入一个元素或者删除一个元素,那么后面的元素必须往前挪或者往后挪
④数组提供角标式访问元素
2. Java内置数组的缺点
①长度不可变,容量不够怎么办
容量不够,那就扩容,比如创建原来数组的几倍长度,然后复制地址指向新数组,原先数组被垃圾回收
②地址连续要提供角标访问很快,但增删元素怎么办
不管增还是删,都要动其他元素,总是要考虑最坏情况
③数组只有length这个属性,没有其他方法
size即表示数据的有效个数,也表示新元素要进入的位置
3. 为什么要调用动态数组
动态数组是顺序存储结构具体实现的核心思想
4. 线性表的定义
零个或多个元素的有限序列
a(i-1)是ai的直接前驱
a (i+1)是ai的直接后继
线性表长度是线性表的有效个数size
抽象类里面所有的方法都没有实现,都是抽象的,那么这个抽象类就可以写成接口
写成接口还有个好处就是防止代码冗余
并且写接口要符合社会现实世界
5.List接口的定义
6.List接口的代码的实现(代码)
package p1.接口;
public interface List<E> extends Iterable {
//在默认表尾添加一个元素
public void add(E element);
//在指定角标处添加元素
public void add(int index,E element);
//删除指定元素
public void remove(E element);
//删除指定角标处的元素,并返回原先的值
public E remove(int index);
//获取指定角标处的元素
public E get(int index);
//修改指定角标index的值为element,并返回原先的值
public E set(int index,E element);
//获取线性表中的元素的个数
public int size();
//查看元素角标第一次出现的位置(从左到右)
public int indexOf(E element);
//判断是否包含元素
public boolean contains(E element);
//判断线性表是否为空
public boolean isEmpty();
//清空线性表
public void clear();
//按照比较器的内容进行排序
public void sort(Comparable<E> c);
//在原线性表中获取一个子线性表,原线性表[fromIndex,toIndex]这个部分
public List<E> subList(int fromIndex,int toIndex);
}
7.线性表的实现ArrayList(代码)
ArrayList就是线性结构顺序存储方式的具体实现,称为线性表
创建ArrayList类实现List接口
定义相关成员属性和构造函数
package p2.线性结构;
import p1.接口.List;
import java.util.Comparator;
import java.util.Iterator;
//自定义的线性表的顺序存储方式
public class ArrayList<E> implements List<E> {
//数组的容器 data.length 指的就是当前数组的容量
private E[] data;
//元素的个数size == 0线性表为空 size == data.length 线性表满了
//size 新元素默认尾部添加时要去的角标
private int size;
//默认容量
private static int DEFAULT_CAPACITY= 10;
//默认构造函数:创建一个默认容量为10的线性表
public ArrayList() {
this(DEFAULT_CAPACITY);
}
public ArrayList(int capacity) {
if(capacity<0){
throw new IllegalArgumentException("capacity must > 0");
}
DEFAULT_CAPACITY = capacity;
data = (E[]) new Object[DEFAULT_CAPACITY];
size = 0;
}
//指定数组的构造函数:传入一个数组,将该数组封装成一个线性表
public ArrayList(E[] arr){
if(arr == null || arr.length == 0){
throw new IllegalArgumentException("arr can not be null");
}
data = (E[]) new Object[DEFAULT_CAPACITY];
for(int i = 0 ; i < arr.length ; i++){
add(arr[i]);
}
}
@Override
public void add(E element) {
add(size,element);
}
@Override
public void add(int index, E element) {
if(index < 0 || index > size ){
throw new IllegalArgumentException("add index out of range");
}
//判断线性表是否为满的状态
if(size==data.length){
resize(2 * data.length);
}
//向后移动元素
for(int i = size -1 ;i >= index ;i--){
data[i+1] = data[i];
}
//将新元素插入到指定位置
data[index] = element;
size++;
}
//扩容/缩容操作 不应该向外提供
private void resize(int newLen) {
E[] newData = (E[]) new Object[newLen];
for(int i = 0; i< size;i++){
newData[i] = data[i];
}
data = newData;
}
@Override
public void remove(E element) {
int index = indexOf(element);
if(index != -1){
remove(index);
}
}
@Override
public E remove(int index) {
if(index < 0 || index >=size){
throw new IllegalArgumentException("remove index out of range");
}
//先保存要删除的值
E ret=data[index];
//移动元素
for(int i = index+1;i <size; i ++ ){
data[i-1] = data[i];
}
size--;
//什么时候缩容
//1.有效元素是容量的1/4
//2.当前容量不得小于等于默认容量
if(size == data.length /4 && data.length >DEFAULT_CAPACITY){
resize(data.length/2);
}
return ret;
}
@Override
public E get(int index) {
if(index < 0 || index>size){
throw new IllegalArgumentException("get index out of range");
}
return data[index];
}
@Override
public E set(int index, E element) {
if(index < 0|| index >= size){
throw new IllegalArgumentException("set index out of range");
}
E ret = data[index];
data[index]= element;
return ret;
}
@Override
public int size() {
return size;
}
//额外添加一个函数,获取线性表中哪个数组的容量
private int getCapacity(){
return data.length;
}
@Override
public int indexOf(E element) {
/*
== 比的是啥?主要看等号的两边是啥
== 两边是基本数据类型的话 比的是值
byte short int long
float double
char boolean
== 两边是引用数据类型的话 比的是地址
数组 字符串 其他的类对象
*/
for(int i =0;i < size;i++){
if(data[i].equals(element)){
return i;
}
}
return -1;
}
@Override
public boolean contains(E element) {
return indexOf(element) != -1;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public void clear() {
data = (E[]) new Object[DEFAULT_CAPACITY];
size = 0;
}
@Override
public void sort(Comparator<E> c) {
if (c == null) {
throw new IllegalArgumentException("comparator can not be null");
}
for (int i = 1; i < size; i++) {
E e = data[i];
int j = 0;
for (j = i; j > 0 && c.compare(data[j - 1], e) > 0; j--) {
data[j] = data[j - 1];
}
data[j] = e;
}
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
if (fromIndex < 0 || toIndex >= size || fromIndex > toIndex) {
throw new IllegalArgumentException("must 0 <= fromIndex <= toIndex <= size - 1");
}
ArrayList<E> list = new ArrayList<>();
for (int i = fromIndex; i <= toIndex; i++) {
list.add(data[i]);
}
return list;
}
@Override
public boolean equals(Object o) {
//1.判空
if (o == null) {
return false;
}
//2.判自己
if (this == o) {
return true;
}
//3.判类型
if (o instanceof ArrayList) {
//4.按照自己的逻辑进行比较
ArrayList<E> other = (ArrayList<E>) o;
//5.先比有效元素的个数
if (size != other.size) {
return false;
}
//6.有效元素个数相等的情况下 逐个比较元素
for (int i = 0; i < size; i++) {
if (!data[i].equals(other.data[i])) {
return false;
}
}
return true;
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
if (isEmpty()) {
sb.append(']');
} else {
for (int i = 0; i < size; i++) {
sb.append(data[i]);
if (i == size - 1) {
sb.append(']');
} else {
sb.append(',');
sb.append(' ');
}
}
}
return sb.toString();
}
@Override
public Iterator iterator() {
return new ArrayListIterator();
}
//创建一个属于ArrayList的迭代器
class ArrayListIterator implements Iterator<E> {
private int cur = 0;
@Override
public boolean hasNext() {
//判断是否有下一个元素
return cur < size;
}
@Override
public E next() {
//如果有下一个元素 则把当前元素返回 并移至到下一个元素
return data[cur++];
}
}
}
8.TestArrayList测试类(代码)
package p0.测试;
import p2.线性结构.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Random;
public class TestArrayList {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
System.out.println(list);
Random random = new Random();
for(int i = 0; i < 10;i++){
list.add(random.nextInt(100));
}
System.out.println(list);
for (int i = 0; i< 10;i++){
list.add(0,i);
}
System.out.println(list);
System.out.println(list.size());
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 -o2;
}
});
System.out.println(list);
for(Object nums : list){
System.out.println(nums);
}
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
}
}
}
1.1.2栈
1.栈的定义
①栈是限定仅在表尾进行插入和删除操作的线性表
②我们把允许插入和删除的一端称为栈顶,另一端称为栈底
③不含任何数据元素的栈称为空栈
④栈又称为后进先出的线性表,简称LIFO结构
⑤线性表是一个线性表,其数据元素具有线性关系,只不过它是一种特殊的线性表而已
⑥栈的插入操作,叫做进栈,也称压栈、入栈
⑦栈的删除操作,叫做出栈,也称弹栈
2.Stack栈接口的定义
3.Stack栈接口的实现(代码)
package p1.接口;
public interface Stack<E> extends Iterable<E> {
public int size();
public boolean isEmpty();
public void push(E element);
public E pop();
public E peek();
public void clear();
}
4.ArrayStack的实现(代码)
package p2.线性结构;
import p1.接口.Stack;
import javax.swing.*;
import java.util.Iterator;
import java.util.Objects;
public class ArrayStack<E> implements Stack<E> {
private ArrayList<E> list;
public ArrayStack(){
list = new ArrayList<>();
}
public ArrayStack(int capacity){
list = new ArrayList<>(capacity);
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public void push(E element) {
list.add(element);
}
@Override
public E pop() {
return list.remove(list.size()-1);
}
@Override
public E peek() {
return list.get(list.size()-1);
}
@Override
public void clear() {
list.clear();
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public String toString() {
return list.toString();
}
@Override
public boolean equals(Object o) {
if(o == null){
return false;
}
if(this == o){
return true;
}
if( o instanceof ArrayStack){
ArrayStack other = (ArrayStack) o;
return this.list.equals(other.list);
}
return false;
}
}
5. TestArrayStack的测试(代码)
package p0.测试;
import p2.线性结构.ArrayStack;
public class TestArrayStack {
public static void main(String[] args) {
ArrayStack<Integer> stack01 = new ArrayStack<>();
ArrayStack<Integer> stack02 = new ArrayStack<>(15);
for(int i = 1;i <=12 ;i++){
stack01.push(i);
stack02.push(i);
}
System.out.println(stack01);
System.out.println(stack02);
System.out.println(stack01.equals(stack02));
System.out.println(stack01.pop());
System.out.println(stack01);
System.out.println(stack01.peek());
}
}
6. 中缀表达式(代码)
package p2.线性结构;
/**
* 飘飘豆芽
*/
public class InfixCalculator4 {
//中缀表达式计算器
public static void main(String[] args) {
String s = "(10+20/2*3)/2+8";
//拆分目标( 10 + 20 / 2 * 3 )/ 2 + 8
//直接拆 ( 1 0 + 2 0 / 2 * 3 ) / 2 + 8
int i = evaluateEpression(s);
System.out.println("(10+20/2*3)/2+8="+i);
}
private static int evaluateEpression(String s) {
ArrayStack<Character> operatorStack = new ArrayStack<>();
ArrayStack<Integer> numberStack = new ArrayStack<>();
String s1 = insertBlanks(s);
String []tokens = s1.split(" ");
for(String token:tokens){
if(token.length()==0){
//去空操作 " "
continue;
}else if(token.equals("+")||token.equals("-")){
while(!operatorStack.isEmpty()&&(operatorStack.peek()=='+'||operatorStack.peek()=='-'||operatorStack.peek()=='*'||operatorStack.peek()=='/')){
processOperator(numberStack,operatorStack);
}
operatorStack.push(token.charAt(0));//'('
}else if(token.equals("*")||token.equals("/")){
while(!operatorStack.isEmpty()&&(operatorStack.peek()=='*'||operatorStack.peek()=='/')){
processOperator(numberStack,operatorStack);
}
operatorStack.push(token.charAt(0)