什么是数据结构:
数据
是描述客观事务的符号,是计算机中可以操作的对象,是能被计算机识别、并输入给计算机处理的符号集合。
数据元素
是组成数据的,有一定意义的基本单位,在计算机中通常作为整体处理,也被称为记录。
数据项
一个数据元素可以由若干个数据项组成。数据项是数据不可分割的最小单位。
数据对象
是性质相同的数据元素的集合,是数据的子集。
数据结构
是相互之间存在一种或多种特定关系的数据元素的集合。
它分为逻辑结构和物理结构(也叫存储结构)。
逻辑结构
是指数据对象中数据元素之间的相互关系。
集合结构
集合结构中的数据元素除了同属一个集合外,它们之间没有其他关系。类似于数学中的集合。
线性结构
线性结构中的数据元素之间是一对一的关系。
树形结构
树形结构中的数据元素之间存在一种一对多的层次关系。
图形结构
图形结构的数据元素是多对多的关系。
物理结构(存储结构)
是指数据的逻辑结构在计算机中的存储形式。
顺序存储结构
是把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。(类比数组Array)
链式存储结构
是把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。(利用地址和指针相配合,迅速定位数据元素)
抽象数据类型
数据类型:是指一组性质相同的值的集合及定义在此集合上的一些操作的总称。
抽象:是指抽取出事物具有的普遍性的本质。
抽象数据类型:是指一个数学模型及定义在该模型上的一组操作。它既取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关。抽象数据类型体现了程序设计中问题分解、抽象和信息隐藏的特性。
算法的定义:
算法是解决特定问题求解步骤的描述。分析问题,一步步求解,并得不到结构,这一系列的步骤就称之为算法
算法时间复杂度
在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n)=O(f(n))。它表示随着问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度。简称时间复杂度。其中f(n)是问题规模n的某个函数
算法时间复杂度主要探究的是问题输入规模N的数量级 不是算法的具体执行次数
常数阶O(1):
就是那些无循环、无递归、与问题输入规模N无关的、逐行执行的代码。
线性阶O(n):
与问题输入规模有关的,主要是一层循环的代码,多个一层循环可以并列但不能包含。
线性阶O(n+m):
和线性阶O(n)一样,只不过我们有两种数据的输入规模。
平方阶O(n^2):
与问题输入规模有关的,主要是二层嵌套循环的代码。
平方阶O(nm):
和平方阶O(n2)一样,只不过我们有两种数据输入规模。
对数阶O(logn):
与问题输入规模有关的,主要是一层循环迭代或递归的代码。
算法分类:
查找算法:线性查找、二分查找、插值查找、斐波那契查找
排序算法: 冒泡排序、选择排序、插入排序、希尔排序、归并排序、 快速排序、堆排序、计数排序、基数排序
图论算法: 深度优先遍历、广度优先遍历、最小生成树、最短路径、 拓扑排序、关键路径
分治回溯 动态规划 背包算法 贪心算法 数论算法
顺序结构(数组)实现线性表
创建一个list接口
package p1.JieKou;
import java.util.Comparator;
//线性表接口定义
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 contain(E element);
//判断线性表是否为空
public boolean isEmpty();
//清空线性表
public void clear();
//按照比较器的内容进行排序
public void sort(Comparator<E> c);
//获取子线性表 原线性表中[fromIndex,toIndex]这个部分
public List<E> subList(int fromIndex, int toIndex);
}
创建一个ArrayList
package p2.XianXingJieGou;
import p1.JieKou.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 capcity) {
if (capcity <= 0) {
throw new IllegalArgumentException("capcity must > 0");
}
DEFAULT_CAPACITY = capcity;
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 range");
}
//先保存要删除的值
E ret = data[index];
//移动元素
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
//什么时候缩容
//1.有效元素是容量的
//当前容量不得小于等于默认容量
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] == element) {
return i;
}
}
return -1;
}
@Override
public boolean contain(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 = 0; 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 <=t oIndex <= size-1");
}
ArrayList<E> list = new ArrayList<>();
for (int i = fromIndex; i <= toIndex; i++) {
list.add(data[i]);
}
return list;
}
@Override
//equals 比较的是ArrayList
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);
*/
@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
//获取当前数据结构(容器)的迭代器
//通过迭代器对象 更方便挨个取出每一个元素
//同时实现了Iterable 可以让当前的数据结构/容器被foreach循环遍历
public Iterator<E> iterator() {
return new ArrayListIterator();
}
//创建一个属于ArratList的迭代器
class ArrayListIterator implements Iterator<E> {
private int cur = 0;
@Override
public boolean hasNext() {//判断是否有下一个元素
return cur < size;
}
@Override
public E next() {//如果有下一个元素 则把当前元素返回 并移至到下一个元素
return data[cur++];
}
}
}
栈的建立
创建一个Stack
package p1.JieKou;
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();
}
创建一个ArrayStack
package p2.XianXingJieGou;
import p1.JieKou.Stack;
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<E> other = (ArrayStack) o;
//转化为两个线性表是否相同
return this.list.equals(other.list);
}
return false;
}
}
中缀表达式计算器的代码实操:
package p2.XianXingJieGou;
//中缀表达式计算器
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();
}
}