java-数据结构-动态数组,线性表,栈

线性表

1.定义:零个或多个元素的有限序列。

n:这里指的有效长度的个数,而不是容量

下列情况不是线性表:

线性表的插入:

1.直接在表尾进行插入

 2.在表中间插入:

 线性表的删除:

1.直接在表尾删除:

2.在表中间进行删除:

线性表接口的一些操作

 //在表尾添加元素
    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); //修改指定角标index处的值为 elemen并返回原先的值
    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);//按照比较器的内容排序
    public List<E> subList(int fromIndex,int toIndex);//获取子线性表

实现接口中的方法

public class AarrayList<E> implements LinearTable<E> {
    //定义数组容器
    private E[] data;
    //元素个数
    private int size;
    //默认容量
    private static int DEFAULT_CAPACITY = 10;

    //默认构造函数
    public AarrayList() {
        data = (E[]) new Object[DEFAULT_CAPACITY];
        size = 0;
    }

    //指定默认容量的构造函数
    public AarrayList(int capacity) {
        if (capacity <= 0) {
            throw new IllegalArgumentException("capacity必须要大于0!");
        }
        DEFAULT_CAPACITY = capacity;
        data = (E[]) new Object[DEFAULT_CAPACITY];
        size = 0;
    }

    //指定数组的构造函数:传入一个数组将该数组封装成一个线性表
    public AarrayList(E[] arr) {
        if (arr == null || arr.length == 0) {
            throw new IllegalArgumentException("arr不能为空");
        }
        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("角标越界");
        }
        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("角标越界");
        }

        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("越界异常");
        }
        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 false;
    }

    @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("不能为空");
        }
        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("角标不合法");
        }
        AarrayList<E> list=new AarrayList<>();
        for (int i = fromIndex; i <=toIndex ; i++) {
            list.add(data[i]);
        }
        return (List<E>) list;
    }
public boolean equals(Object o){
        if (o==null){
            return  false;
        }
        if (this==o){
            return  true;
        }
        if(o instanceof  AarrayList){
            AarrayList<E> other= (AarrayList<E>) o;
        if (size!=other.size){
            return false;
        }
            for (int i = 0; i <size ; i++) {
                if(data[i].equals(other.data)){
                    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();
    }
/*获取当前这个数据结构、容器  的迭代器
 通过迭代器  更方便取出每一个元素
 同时  实现了Iterable 可以让当前数据结构 更好的遍历
*/
    @Override
    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++];
    }
}
}

1.栈是限定仅在表尾进行插入和删除操作的线性表。(也可以说栈是一个特殊的线性表)

2.我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)

3.不含任何数据元素的栈称为空栈
4.栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构
5.栈本身是一个线性表,其数据元素具有线性关系,只不过它是一种特殊的线性表而已
6.栈的插入操作,叫作进栈,也称压栈、入栈 。栈的删除操作,叫作出栈,也称弹栈。

问题:栈既然是一种特殊的线性表,那么可以不可以直接继承线性表?

可以继承线性表,但是没有必要,因为线性表的许多功能,而栈用不到,所以不需要继承。

栈的接口:


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

实现接口中的方法:

public class ArrayStack<E>implements stack<E>{
   private AarrayList<E>list;

    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }

    public ArrayStack(){
       list=new AarrayList<>();
   }
   public ArrayStack(int capacity){
       list=new AarrayList<>(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 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;
    }
}

栈的实例:

中缀计算

(只符合计算中只有加减乘除计算)  例:对(10+20/2*3)/2+8 进行计算

第一步:先将(10+20/2*3)/2+8进行格式化  每个字符前后都加一个空格, ( 10 + 20 / 2 * 3 )  / 2 + 8

第二步:创建两个栈,一个栈是专门存放符号,一个栈是专门存放数字。然后遍历。第一次先遍历的是(  ,由于“(  ” 为栈底,无计算符号,即(  放入符号栈,然后遍历到10,直接放入数字栈,然后遍历到 + ,先判断栈顶(此时栈顶为“(  ” ) 没有比+更高一级的运算符(判断没有),则继续遍历到20,20存放在数字栈中,继续遍历到  /  判断 (由于此时栈顶为+,但是+运算符的运算优先级没有/高,所以不进行+运算),则将/ 放入符号栈中,继续遍历到2,直接放入数字栈,继续遍历到 *(判断,此时栈顶为/ ,因为*和/运算级别相同则计算先计算先进入栈的/),计算完成后将计算的值放入数字栈中。将*入栈。

 继续遍历到3直接进入数字栈,继续遍历到  ),因为是()让括号中的内容提升优先级,那么遍历到右括号,则将括号内的运算内容全部计算完毕,那么此时符号栈中有*和+,根据优先,先算*号,再算+,然后清楚左括号。右括号不进栈。

 

 然后继续遍历到/(由于栈中没有符号)则/直接入栈,继续遍历到2直接放入数字栈中,在遍历到+,此时栈顶是/(由于/的优先级比+高,所以先计算/)然后将+入栈然后在遍历到8,将8直接放入数字栈中,当全部遍历完,进行最后的计算。返回计算结果。

 

 代码实现:

public class infixcalculwtor {
    public static void main(String[] args) {
        String expression="(10+20/2*3)/2+8";

        expression=insertBlanks(expression);
        System.out.println(expression);
     int result=evaluateExpression(expression);
        System.out.println(result);
    }
    private static int evaluateExpression(String expression){
        //两个辅助栈,一个字符栈,一个数字栈
        ArrayStack<Character> operatorStack= new ArrayStack<Character>();
        ArrayStack<Integer> numberStack= new ArrayStack<Integer>();
       //格式化表达式
        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();
        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();
    }
}

中缀表达式转前缀表达式

  前缀表达式: 10 20 2 / 3 * + 2 / 8 +   中缀表达式:(10+20/2*3)/2+8

如何转呢?  还是利用两个栈,一个放计算符,一个放前缀表达式栈。和中缀表达式一样,先将表达式格式化(每个字符两边都加个空格),开始逐个遍历,计算符栈,入栈规则(若栈为空则入栈,若遍历到‘(  ’ 则入栈,若比栈顶优先级大,入栈。若比栈顶优先级小,入栈。若同级,则先让栈顶弹出,再入栈。弹出的那个字符再入前缀表达式栈,若遍历到右括号,则将括号内计算符挨个弹出并进入到前缀表达式栈内,左括号不用进表达式栈)。

 

public static void main(String[] args) {
        String expression = "(10+20/2*3)/2+8";
        expression = infixToSuffix(expression);
        System.out.println(expression);
    }
   public static String infixToSuffix(String expression) {
        //操作符的栈
        ArrayStack<String> opStack = new ArrayStack<String>();
        //后缀表达式的线性表
        ArrayList<String> suffixList = new ArrayList<>();
        //格式化表达式
        expression = insertBlanks(expression);
        String[] tokens = expression.split(" ");
        for (String token : tokens) {
            //过滤空串
            if (token.length() == 0) {
                continue;
            }
            //判断操作符+ - * /
            if (isOperator(token)) {
                /*
                什么时候操作符进栈?
                1.如果栈为空
                2.如果栈顶是 (
                3.如果栈顶是操作符,且优先级比当前token小

                什么时候需要将栈顶操作符出栈?
                1.栈顶操作符的优先级 >= 当前token
                */
                while (true) {
                    if (opStack.isEmpty() || opStack.peek().equals("(") || priority(opStack.peek()) < priority(token)) {
                        opStack.push(token);
                        break;
                    }
                    suffixList.add(opStack.pop());
                }
            } else if (token.equals("(")) {
                opStack.push(token);
            } else if (token.equals(")")) {
                while (!opStack.peek().equals("(")) {
                    suffixList.add(opStack.pop());
                }
                opStack.pop();
            } else if (isNumber(token)) {
                suffixList.add(token);
            } else {
                throw new IllegalArgumentException("wrong char :" + expression);
            }
        }
        while (!opStack.isEmpty()) {
            suffixList.add(opStack.pop());
        }
        //将数字元素和操作符元素进行拼接
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < suffixList.size(); i++) {
            sb.append(suffixList.get(i));
            sb.append(' ');
        }
        return sb.toString();
    }

    private static int priority(String token) {
        if (token.equals("+") || token.equals("-")) {
            return 0;
        }
        if (token.equals("*") || token.equals("/")) {
            return 1;
        }
        return -1;
    }

    private static boolean isNumber(String token) {
        return token.matches("\\d+");
    }

    private static boolean isOperator(String token) {
        return token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/");
    }

    //对原表达式进行格式化处理 给所有的非数字字符两边添加空格
    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();
    }

 

十进制转十六制

             例如:654321        根据计算每次的余数分别为  1,15,11,15,9.即1,F,B,F,9

每得到一个一个余数入栈,然后在依次弹出。结果为9,F,B,F,1.

                                   

 public static void main(String[] args) {
        int num = 654321;
        ArrayStack<String> stack = new ArrayStack<String>();
        while (num != 0) {
            int a = num % 16;
            if (a < 10) {
                stack.push(a + " ");
            } else {
                //10-A 11-B 12-C 13-D 14-E 15-F
                //65    66   67  68   69    70
                stack.push((char) (a + 55) + " ");
            }
            num /= 16;
        }
        StringBuilder sb=new StringBuilder();
        while (!stack.isEmpty()){
            sb.append(stack.pop());
        }
        System.out.println(sb.toString());
    }

回文问题

例如“ 上海自来水来自海上”   将水前的的字依次入栈,然后在将水以后的字入栈,判断入栈前,若与栈顶相同,则将栈顶出栈,如果栈为空,则是回文。

private static void splution() {
        String expression = "上海自来水来自海上";
        ArrayStack<Character> stack = new ArrayStack<Character>();
        for (int i = 0; i < expression.length(); i++) {
            if (expression.length() % 2 == 1 && i == expression.length() / 2){
                continue;
            }
            char c=expression.charAt(i);
            if (stack.isEmpty()){
                stack.push(c);
            }else {
                if (c!=stack.peek()){
                    stack.push(c);
                }else {
                    stack.pop();
                }
            }
        }
        System.out.println(stack.isEmpty());
    }

括号匹配问题

例如:{ ( ) [ ] }   因为相对应的{  },( ),[ ]  他们的差值不是-1就是-2,所以根据这个特性在利用栈。

  String str="{()[]}";
        ArrayStack<Character>stack= new ArrayStack<Character>();
        for (int i = 0; i <str.length() ; i++) {
            char c=str.charAt(i);
            if (stack.isEmpty()){
                stack.push(c);
            }else {
                char top=stack.peek();
                if (top-c==-1||top-c==-2){
                    stack.pop();
                }else {
                    stack.push(c);
                }
            }
        }
        System.out.println(stack.isEmpty());
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值