数据结构与算法
数据结构概论
线性结构:线性结构中的数据元素之间是一对一的关系
树形结构:树形结构中的数据元素之间存在一种一对多的层次关系
图形结构:线性结构中的数据元素之间是多对多的关系
关系在电脑中的结构 物理结构
顺序存储结构:开辟一组连续的空间存储数据
通常用数组来实现,数组中空间本身是连续的,保证了数据之间的关系
链式存储结构:开辟一组随机的空间存储数据,通常使用节点
通常使用节点来实现,节点不仅要存储数据还要存储下一个节点的位置以保证数据之间的关系
线性结构
树形结构
图形结构
算法概述
什么是算法
是解决特定问题求解步骤的描述,分析问题,一步步求解,并得到结果,这一系列步骤称为算法
算法时间复杂度
算法时间复杂度主要探究的问题是输入规模N的数量级,不是算法的具体执行次数
常见阶比较
Java数组:
特点
-
数组长度一旦确定不可更改
-
数组只能存储同一类型的数据(上下兼容)
-
数组中每个存储空间地址连续且相等
-
提供角标的方式访问元素
缺点
-
长度不可变
-
地址连续下标访问快,但增删元素麻烦
-
数组只有一个length属性,没有其他方法
线性表的实现
线性表的定义
零个或多个的有限序列
List接口的定义
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);
//修改指定位置的元素,并返回原先的值
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);
//获取子线性表 原线性表中(int fromIndex,int toIndex)这个部分
public List<E> subList(int fromIndex,int toIndex);
}
线性表ArrayList的实现
public class ArrayList<E> implements List<E> {
//数组容器
private E[] data;
//元素的个数
//默认添加的角标
private int size;
//数组默认长度
private static int DEFAULT_CAPACITY =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;
}
public ArrayList(E[]arr) {
if(arr==null || arr.length==0){
throw new IllegalArgumentException("capacity小于0");
}
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(data.length * 2);
}
//向后移动元素
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
//将新元素插入到指定位置
data[index] = element;
size++;
}
//扩容缩容
private void resize(int newsize) {
E[] newData = (E[]) new Object[newsize];
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("越界");
}
E ret = data[index];
for (int i = index+1;i < size;i++){
data[i-1] = data[i];
}
size--;
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("越界");
}
return data[index];
}
//修改指定下标的元素
@Override
public E set(int index, E element) {
if (index < 0 || index >= size){
throw new IllegalArgumentException("越界");
}
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) {
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("compare is null");
}
for (int i = 0; i < size; i++){
int j = 0;
E a = data[i];
for (j = i; j > 0 && c.compare(data[j-1],a)>0; j--){
data[j] = data[j-1];
}
data[j] = a;
}
}
//截取一段表
@Override
public List<E> subList(int fromIndex, int toIndex) {
if (fromIndex < 0 || toIndex >= size || fromIndex > toIndex){
throw new IllegalArgumentException("角标输入错误");
}
ArrayList<E> list = new ArrayList<>();
for (int i = fromIndex; i <= toIndex; i++){
list.add(data[i]);
}
return list;
}
//比较
@Override
public boolean equals(Object o){
//判空
if (o == null){
return false;
}
//判自己
if (this == o){
return true;
}
//判类型
if (o instanceof ArrayList) {
ArrayList<E> other = (ArrayList<E>) o;
if ( this.size != other.size){
return false;
}
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<E> iterator() {
return new ArrayListTterator();
}
class ArrayListTterator implements Iterator<E>{
private int cur =0;
@Override
public boolean hasNext() { //判断是否有下一个元素
return cur < size;
}
@Override
public E next() { //如果有下一个元素,则把当前元素返回,并移至下一个元素
return data[cur++];
}
}
}
栈的定义
栈是限定仅在表头进行插入和删除的线性表
-
我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底
-
不含任何数据元素的栈称为空栈
-
栈又称为后进先出的线性表,简称LIFO结构
-
栈本身是一个线性表,其数据元素具有线性关系,只不过它是一种特殊的线性表而已
-
栈的插入操作,叫作进栈,也称压栈、入栈;栈的删除操作,叫作出栈,也称弹栈
Stack栈的接口
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的实现
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 null;
}
@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;
}
}
中缀表达式
是一个通用的算术或逻辑公式表示方法,操作符是以中缀形式处于操作数的中间(3+4)
public class Calculator {
public static void main(String[] args) {
String express = "(10+20/2*3)/2+7";
int result = evaluateExpression(express);
System.out.println(result);
}
private static int evaluateExpression(String express) {
ArrayStack<Character> operatorStack = new ArrayStack<>();
ArrayStack<Integer> numberStack = new ArrayStack<>();
express = insert(express);
String[] tokens = express.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() == '/') ){
//需要弹栈运算
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 运算符 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 insert(String express){
StringBuilder sb = new StringBuilder();
for(int i = 0; i < express.length(); i++){
char c = express.charAt(i);
if(c == '(' || c == ')' || c == '+' || c == '-' || c == '/' || c == '*'){
sb.append(" ");
sb.append(c);
sb.append(" ");
}else{
sb.append(c);
}
}
return sb.toString();
}
}