算法与数据结构 01 线性结构

  1. 线性表

(1) 线性表是由n(n>=0)个数据元素所构成的有限序列。
(2) 对于同一个线性表,其每一个数据元素的虽然有所不同,但必须具有相同的数据类型;同时,数据元素之间具有一种线性或“一对一”的逻辑关系:

  • 第一个数据元素没有前驱,这个数据元素称为开始结点;
  • 最后一个数据元素没有后继,这个数据元素称为终端结点;
  • 除了首尾数据元素之外,其他数据元素有且仅有一个前驱和一个后继。

(3) 上述的逻辑关系就是线性结构。线性表就是一种线性结构。
(4) 线性表的基本操作:

  • clear():将一个已经存在的线性表置空
  • isEmpty():判断线性表是否为空。若为空,返回true;不为空,返回false;
  • length():求线性表中的元素个数,并返回其值
  • get(i):读取并返回线性表中的第i个元素的值,其中0<= i <=length() -1
  • insert( i,x):在线性表的第i个元素之前插入一个值为x的数据元素。其中0<= i <=length(),当i=0时,在表头插入;当i=length()时,在表尾插入
  • remove(i ):删除并返回线性表中第i个元素。其中0<= i <=length() -1
  • indexOf( x ):返回线性表中首次出现指定元素位序号,不包含此元素则返回 -1

创建接口:

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);
}

线性表的简单操作实现

package 线性结构;

import 数据结构接口.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;
  }

  //传入一个数组 将该数组封装成为一个线性表
  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) {
    for (int i=0;i<size;i++){
      if (data[i].equals(element)){
        /*
        == 比的是啥?主要看等号的两边是啥
        == 两边是基本数据类型的话 比的是值
            byte short int long
            float double
            char boolean
        == 两边是引用数据类型的话 比的是地址
            数组 字符串 其他的类对象
        */
        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<= formIndex <= 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;
  }
  /*
  [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() ;
  }

  //获取当前这个数据结构/容器 的 迭代器
  //通过迭代器对象 更方便挨个取出每一个元素
  //同时 实现了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++];
    }
  }
}

测试:

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    System.out.println(list);
    Random random = new Random();//引入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() + " ");
    }
  }
}
//输出结果
[]
[15, 47, 24, 40, 90, 35, 87, 84, 18, 17]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 47, 24, 40, 90, 35, 87, 84, 18, 17]
[90, 87, 84, 47, 40, 35, 24, 18, 17, 15, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

  • (1)栈是一种特殊的线性表,栈中的数据元素以及数据元素之间的逻辑关系和线性表相同,两者之间的区别主要在:
  • 线性表的插入和删除操作可以在任意指定位置进行,而栈只允许在末尾进行。
    (2)将插入行为称为入栈,删除行为称为出栈。
    (3) 栈的基本操作与线性表基本相同:
  • 取栈顶元素peek():读取栈顶元素并返回其值,若为空,则返回null
  • 入栈操作push():将数据元素压入栈顶
  • 出栈操作pop():删除并返回栈顶元素

(4)代码实现
创建接口

public interface Stack<E> extends Iterable {
  public int size();
  public boolean isEmpty();
  //入栈 出栈一个元素 再线性表的表尾添加一个元素
  public void push(E element);
  //出栈 弹出一个元素 在线性表的末尾删除一个元素
  public E pop();
  //查看当前栈顶元素
  public E peek();
  public void clear();
}

栈的简单实现

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 Iterator<E> iterator() {
    return list.iterator();
  }

  @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 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;
  }
}

测试

  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());
  }
}
//输出结果
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
true
12
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
11
  1. 中缀计算
    中缀表达式:是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
    与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
    与前缀或后缀记法不同的是,中缀记法中括号是必需的。计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。

在这里插入图片描述

例如有这样一个字符串表达式:"(10+20/2*3)/2+8"
首先对它的运算符和提高优先级符号"()“的左右进行添加” "(空格)的操作,然后在运用java的split方法切割 ,就能实现对表达式的符号数字的分类识别,最后再用两个ArrayStack存放操作符和数字,最后根据不同的操作符与操作符栈栈顶遇到的几种情况分类,最后再书写每次计算,弹两个数字和一个操作符,结果放入数字栈的方法实现一个式子的计算。

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) {
      //过滤空串
      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();
  }
}
//输出结果
 28
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值