目录
1线性结构
1.1逻辑结构和物理结构
1.1.1数据结构的逻辑结构主要是:
1线性结构 :线性结构中的数据元素之间是一对一的关系
2树形结构 :树形结构中的数据元素之间存在一种一对多的层次关系
3图形结构:图形结构的数据元素是多对多的关系
1.1.2数据结构的物理结构主要是:
顺序存储结构:
开辟一组连续的空间存储数据 通常用数组来实现,数组中空间本身是连续的,保证了数据之间的关系。
链式存储结构:
开辟一组随机的空间存储数据 通常用节点来实现,节点不仅要存储数据还要存储下一个节点的位置以保证数据之间的关系。
1.2线性结构 + 顺序存储 = ?
1.线性表
2.栈
3.双端栈
4.队列
5.循环队列
6。双端队列
1.3静态数组与动态数组
1.3.1 Java内置数组的特点:
1.数组的长度一旦确定则不可更改
2.数组只能存储同一类型的数据
3.数组中每个存储空间地址是连续且相等的
4.数组提供角标的方式访问元素
1.3.2 Java内置数组的缺点:
长度不可变,容量不够用怎么办 (容量不够,那就扩容)
地址连续且提供角标访问很快,但增删元素怎么办 (元素删除后剩下的元素向前移动)
数组只有length这个属性,没有其他的方法(元素添加后,后面的元素向后移动
1.3.3 为什么强调动态数组?
其实,动态数组就是顺序存储结构具体实现的核心思想
1.4线性表
1.4.1 线性表的定义:
1.零个或多个元素的有限序列
2.
3.
1.4.2 List接口的定义:
1.既然线性结构可以由顺序存储结构和链式存储结构实现
2.那么将两者对线性结构共同的操作进行抽取,定义出线性结构的接口
package P1.接口;
import java.util.Comparator;
import java.util.Iterator;
//线性表接口定义
public interface List<E> extends Iterable<E> {
//默认在表尾添加一个元素
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(Comparator<E> c);
//获取子线性表 原线性表中【fromIndex,toIndex)这个部分
public List<E> subList(int fromIndex,int toIndex);
//
public String toString();
//
public boolean equals(Object o);
}
1.4.3线性表的实现ArrayList
1.创建ArrayList类实现List接口
2.定义相关成员属性和构造函数
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() {
data = (E[]) new Object[DEFAULT_CAPACITY];
size = 0;
}
//指定默认容量的构造函数:创建一个指定容量的线性表
public ArrayList(int capacity) {
if (capacity <= 0) {
throw new IllegalArgumentException("capacity must >0");
}
DEFAULT_CAPACITY = capacity;
data = (E[]) new Object[DEFAULT_CAPACITY];
size = 0;
}
//指定数组的构造函数:传入一个数组将该数组封装成为一个线性表
//[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
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 rang");
}
//先保存要删除的值
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 rang");
}
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");
}
ArrayList<E> list = new ArrayList<>();
for(int i = fromIndex;i<=toIndex;i++){
list.add(data[i]);
}
return list;
}
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;
}
/*
[1,2,3,4,5,6]
[]
Arrays.toString(arr);
*/
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();
}
//获取当前这个数据结构/容器的迭代器
//通过迭代器对象更方便挨个取出每一个元素
//同时 实现了Iterable 可以当前的数据结构/容器 被foreach循环遍历
@Override
public Iterator<E> 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++];
}
}
}
1.4.4 ArrayListTest类:
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);
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println(list);
for (Integer num : list) {
System.out.println(num);
}
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
1.5栈
1.5.1栈的定义:
1.栈是限定仅在表尾进行插入和删除操作的线性表
2.我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底3(bottom)
3.不含任何数据元素的栈称为空栈 栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构
4.栈本身是一个线性表,其数据元素具有线性关系,只不过它是一种特殊的线性表而已
5.栈的插入操作,叫作进栈,也称压栈、入栈
6.栈的删除操作,叫作出栈,也称弹栈
1.5.2 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();
}
1.5.3 ArrayStack类
package P2.线性结构;
import P1.接口.Stack;
import java.util.Iterator;
public class ArrayStack<E> implements Stack<E> {
private ArrayList<E> list;
public ArrayStack() {
list = new ArrayList<>();
}
public ArrayStack(int caapcity) {
list = new ArrayList<>(caapcity);
}
@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 false;
}
}
2 中缀表达式
是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4)
与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
与前缀或后缀记法不同的是,中缀记法中括号是必需的。
2.1中缀表达式计算器
package P2.线性结构;
//中缀表达式计算器
public class InfixCalculator {
public static void main(String[] args) {
String expression = "(10+20/2*3)/2+8";
try {
int result = evaluateExpression(expression);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Wrong expression :" + expression);
}
}
private static int evaluateExpression(String expression) {
//需要两个辅助栈
ArrayStack<Character> operatorStack = new ArrayStack<>();
ArrayStack<Integer> numberStack = new ArrayStack<>();
//格式化表达式
expression = insertBlanks(expression);
String[] tokens = expression.split(" ");
for (String token : tokens) { //token == tokens[i]
//过滤空串
if (token.length() == 0) {
continue;
//遍历到 + - 号
} else if (token.equals("+") || token.equals("-")) {
while (!operatorStack.isEmpty() && (operatorStack.peek() == '+' || operatorStack.peek() == '-' || operatorStack.peek() == '*' || operatorStack.peek() == '/')) {
//如果之前是别的+ - * / 则需要弹栈 并计算
processAnOperator(numberStack, operatorStack);
}
//如果操作符栈为空 或者 不为空但栈顶为(
operatorStack.push(token.charAt(0));
//遍历到 * / 号
} else if (token.equals("*") || token.equals("/")) {
while (!operatorStack.isEmpty() && (operatorStack.peek() == '*' || operatorStack.peek() == '/')) {
//如果之前是别的* / 则需要弹栈 并计算
processAnOperator(numberStack, operatorStack);
}
//如果操作符栈为空 或者 不为空但栈顶为(
operatorStack.push(token.charAt(0));
//遍历到 (
} else if (token.equals("(")) {
operatorStack.push(token.charAt(0));
//遍历到 )
} else if (token.equals(")")) {
//只要操作符栈的栈顶不是左括号( 就挨个弹栈计算即可
while (operatorStack.peek() != '(') {
processAnOperator(numberStack, operatorStack);
}
//最后 清掉左括号
operatorStack.pop();
//遍历到数字
} else {
numberStack.push(new Integer(token));
}
}
//处理最后面的操作符
while (!operatorStack.isEmpty()) {
processAnOperator(numberStack, operatorStack);
}
return numberStack.pop();
}
//操作符栈弹栈一个元素 数字栈弹栈两个数字 进行计算 并将新的结果进栈到数字栈
private static void processAnOperator(ArrayStack<Integer> numberStack, ArrayStack<Character> operatorStack) {
char op = operatorStack.pop();
int num1 = numberStack.pop();
int num2 = numberStack.pop();
//num2 op num1
if (op == '+') {
numberStack.push(num2 + num1);
} else if (op == '-') {
numberStack.push(num2 - num1);
} else if (op == '*') {
numberStack.push(num2 * num1);
} else {
numberStack.push(num2 / num1);
}
}
//对原表达式进行格式化处理 给所有的非数字字符两边添加空格
private static String insertBlanks(String expression) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/') {
sb.append(' ');
sb.append(c);
sb.append(' ');
} else {
sb.append(c);
}
}
return sb.toString();
}
}