栈的定义:

栈(stack)是一种用于存储数据的简单数据结构。栈一个有序线性表,只能在表的一端(PS:栈顶)执行插人和删除操作。最后插人的元素将被第一个删除。所以,栈也称为后进先出(Last In First Out,LIFO)或先进后出(First In Last Out,FILO)线性表。

Java 集合框架中的 Stack 继承自 Vector:

  • 由于 Vector 有 4 个构造函数,加上 Stack 本身的一种,也就是说有 5 中创建 Stack 的方法
  • 跟 Vector 一样,它是可以由数组实现的栈

栈的几种主要基本操作:

  • void push(int data):入栈(将数据data插入到栈中)
  • int pop():出栈(删除并返回最后一个插入栈的元素)
  • int top():返回最后一个插入栈的元素,但不删除
  • int size():返回存储在栈中的元素个数
  • boolean isEmpty():返回栈是否是空栈
  • boolean isFull():返回是否是满栈
  • void Clear():清除整个栈

栈的应用:

  • 符号匹配
  • HTML和XML文件中的标签匹配(实质还是符号匹配)
  • 实现函数调用
  • 文本编辑器中的撤销
  • 网页浏览器中已访问页面的历史记录
  • 作为一个算法的辅助数据结构

栈的基本方法:

public interface Stack<E> extends Iterable<E> {//获取栈的size大小public int size();//判断栈是否为空public boolean isEmpty();//入栈 进栈一个元素 在线性表的表尾添加一个元素public void push(E element);//出栈 弹出一个元素 在线性表的表尾删除一个元素public E pop();//查看当前栈顶元素 并不是移除 查看线性表中最后一个元素public E peek();//对当前栈进行清空public void clear();
}

栈的几种实现方式

  1. 基于简单数组的实现方式
  2. 基于动态数组的实现方式
  3. 基于链表的实现方式
  4. 基于队列的实现方式

1.基于简单数组的实现:

基于简单数组实现一个栈,其基本思路是这样的:从左至右向数组中添加所有的元素,并定义一个变量用来记录数组当前栈顶(top)元素的下标。当数组存满了栈元素时,执行入栈(插入元素)操作将抛出栈满异常;当对一个没有存储栈元素的数组执行出栈(删除元素)操作将抛出栈空异常,当然,这种实现方式有一个很明显的局限性。那就是:栈的最大空间必须预先声明且不能改变。试图对一个满栈执行入栈操作将会产生异常。

2.基于动态数组的实现:

基于动态数组的实现一个栈,其基本思路跟上面类似。不同的是,这种方式下当数组中存储的元素达到一定量时(如:数组空间的0.75或者整个数组空间),这时我们通常会选择新建一个比原数组空间大一倍的新数组,然后将原数组按照原来的顺序复制进去,接着便可以继续进行入栈操作了。

import p1.Stack;(上方的Stack包)import java.util.Iterator;public class ArrayStack<E> implements Stack<E> {//定义私有变量Listprivate ArrayList<E> list;//默认构造public ArrayStack() {list = new ArrayList<>();}//自己定义数组长度public ArrayStack(int capacity) {list = new ArrayList<>(capacity);}//size实现@Overridepublic int size() {return list.size();}//判空实现@Overridepublic boolean isEmpty() {return list.isEmpty();}//push方法@Overridepublic void push(E element) {list.add(element);}//pop方法实现@Overridepublic E pop() {return list.remove(list.size() - 1);}//peek实现@Overridepublic E peek() {return list.get(list.size() - 1);}//clear方法@Overridepublic void clear() {list.clear();}//迭代方法@Overridepublic Iterator<E> iterator() {return list.iterator();}//toString方法实现@Overridepublic String toString() {return list.toString();}//继承Object equals方法@Overridepublic 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.基于链表的实现:

基于链表实现一个栈,其基本思路是这样的:通过在链表的表头插入元素的方式来实现push操作;通过删除链表的表头节点的方式来实现pop操作.

public class SinglyNode<K extends Object> {private K data; // 数据private SinglyNode<K> next; // 该节点的下个节点public SinglyNode(K data) {this.data = data;}public SinglyNode(K data, SinglyNode<K> next) {this.data = data;this.next = next;}public K getData() {return data;}public void setData(K data) {this.data = data;}public SinglyNode<K> getNext() {return next;}public void setNext(SinglyNode<K> next) {this.next = next;}@Overridepublic String toString() {return "SinglyNode [data=" + data + "]";}}
public class LinkStack<K extends Object> implements Stack<K> {private SinglyNode<K> headNode;//是否为满栈public boolean isFull() {return false;}//是否为空public boolean isEmpty(){return headNode == null ? true : false;}//入栈public void push(K data){if(headNode == null){headNode = new SinglyNode<K>(data);}else{SinglyNode<K> newNode = new SinglyNode<K>(data);newNode.setNext(headNode);headNode = newNode;}}//出栈public K pop(){if(headNode == null){throw new EmptyStackException();}else{K data = headNode.getData();headNode = headNode.getNext();return data;}}//返回栈顶元素public K top(){if(headNode == null){throw new EmptyStackException();}else{return headNode.getData();}}//返回栈中元素个数public int size(){if(headNode == null){return 0;}else{int length = 0;SinglyNode<K> currentNode = headNode;while (currentNode != null) {length++;currentNode = currentNode.getNext();}return length;}}//清空栈public void ClearStack(){headNode = null;}//遍历栈从前往后@Overridepublic void print() {SinglyNode<K> tmpNode = headNode;printFromEnd(tmpNode);}//遍历栈从后往前public void printFromEnd(SinglyNode<K> headNode){if(headNode != null){if(headNode.getNext() != null){printFromEnd(headNode.getNext());}System.out.print(headNode.getData() + " ");}}}

基于数组实现和基于链表实现的比较

(1)基于数组实现的栈:

  • 各个操作都是常数时间开销
  • 每隔一段时间进行的倍增操作的时间开销较大

(2)基于链表实现的栈:

  • 栈规模的增加和减小都很容易
  • 各个操作都是常数时间开销
  • 每个操作都需要使用额外的空间和时间开销来处理指针

4.基于队列实现栈:

import java.util.Iterator;//队列实现栈
public class QueueToStack {public static void main(String[] args) {StackImplByQueue<Integer> stack = new StackImplByQueue<>();System.out.println(stack);for (int i = 1; i <= 5; i++) {stack.push(i); //队列A}System.out.println(stack.toString());System.out.println(stack.pop());System.out.println(stack);  //队列B}
}class StackImplByQueue<E> implements Stack<E> { //上方的栈调用private ArrayQueue<E> queueA;private ArrayQueue<E> queueB;public StackImplByQueue() {queueA = new ArrayQueue<>();queueB = new ArrayQueue<>();}@Overridepublic int size() {if (queueA.isEmpty() && queueB.isEmpty()) {return 0;} else if (!queueA.isEmpty()) {return queueA.size();} else {return queueB.size();}}@Overridepublic boolean isEmpty() {return queueA.isEmpty() && queueB.isEmpty();}@Overridepublic void push(E element) {if (queueA.isEmpty() && queueB.isEmpty()) {queueA.offer(element);} else if (!queueA.isEmpty()) {queueA.offer(element);} else {queueB.offer(element);}}@Overridepublic E pop() {if (isEmpty()) {return null;}E ret = null;if (!queueA.isEmpty()) {while (queueA.size() != 1) {queueB.offer(queueA.poll());}ret = queueA.poll();} else {while (queueB.size() != 1) {queueA.offer(queueB.poll());}ret = queueB.poll();}return ret;}@Overridepublic E peek() {if (isEmpty()) {return null;}E ret = null;if (!queueA.isEmpty()) {while (queueA.size() != 1) {queueB.offer(queueA.poll());}ret = queueA.poll();queueB.offer(ret);} else {while (queueB.size() != 1) {queueA.offer(queueB.poll());}ret = queueB.poll();queueA.offer(ret);}return ret;}@Overridepublic void clear() {queueA.clear();queueB.clear();}@Overridepublic Iterator<E> iterator() {if (isEmpty()) {return queueA.iterator();} else if (!queueA.isEmpty()) {return queueA.iterator();} else {return queueB.iterator();}}@Overridepublic String toString() {if (isEmpty()) {return "[]";} else if (!queueA.isEmpty()) {return queueA.toString();} else {return queueB.toString();}}}

Java 集合框架中的 Stack 具有以下特点:

  • 继承自 Vector
  • 有 5 种创建 Stack 的方法
  • 采用数组实现
  • 除了 push(),剩下的方法都是同步的。

双端栈:

双端栈定义:

是指一个线性表的两端当做栈底,分别进行入栈和出栈操作,主要利用了栈:栈底不变,栈顶变化的特征;

双端栈是线性表的一种,更是栈的一个特殊分类,可用借用动态数组+栈的组合实现。

双端栈实现方法以及基本方法:

import java.util.Iterator;//双端栈
public class ArrayDoubleEndStack<E> implements Iterable<E> {//左端栈的栈顶private int ltop;//右端栈的栈顶private int rtop;//存储元素的容器private E[] data;//数组容器的默认容量private static int DEFAULT_CAPACITY = 10;//构造public ArrayDoubleEndStack() {data = (E[]) new Object[DEFAULT_CAPACITY];ltop = -1;rtop = data.length;}//左入栈public void pushLeft(E element) {if (ltop + 1 == rtop) {resize(data.length * 2);}data[++ltop] = element;}//右入栈public void pushRight(E element) {if (ltop + 1 == rtop) {resize(data.length * 2);}data[--rtop] = element;}//扩容private void resize(int newLen) {E[] newData = (E[]) new Object[newLen];//复制左端栈的元素for (int i = 0; i <= ltop; i++) {newData[i] = data[i];}//复制右端栈的元素int index = rtop;for (int i = newLen - sizeRight(); i < newLen; i++) {newData[i] = data[index++];}rtop = newLen - sizeRight();data = newData;}//左出栈public E popLeft() {if (isLeftEmpty()) {throw new IllegalArgumentException("left stack is null");}E ret = data[ltop--];if (sizeLeft() + sizeRight() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {resize(data.length / 2);}return ret;}//右出栈public E popRight() {if (isRightEmpty()) {throw new IllegalArgumentException("right stack is null");}E ret = data[rtop++];if (sizeLeft() + sizeRight() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {resize(data.length / 2);}return ret;}//获取左栈顶public E peekLeft() {if (isLeftEmpty()) {throw new IllegalArgumentException("left stack is null");}return data[ltop];}//获取右栈顶public E peekRight() {if (isRightEmpty()) {throw new IllegalArgumentException("right stack is null");}return data[rtop];}//判断是否左边为空public boolean isLeftEmpty() {return ltop == -1;}//判断是否右边为空public boolean isRightEmpty() {return rtop == data.length;}//通过左指针获取长度public int sizeLeft() {return ltop + 1;}//通过右指针获取长度public int sizeRigh() {return data.length - rtop;}//重写toString方法@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append('[');if (isLeftEmpty() && isRightEmpty()) {sb.append(']');return sb.toString();}//先左边for (int i = 0; i <= ltop; i++) {sb.append(data[i]);if (i == ltop && isRightEmpty()) {sb.append(']');return sb.toString();} else {sb.append(',');}}//后右边for (int i = rtop; i < data.length; i++) {sb.append(data[i]);if (i == data.length - 1) {sb.append(']');} else {sb.append(',');}}return sb.toString();}//迭代器@Overridepublic Iterator<E> iterator() {return new ArrayDoubleEndStackIterator();}class ArrayDoubleEndStackIterator implements Iterator<E> {private ArrayList<E> list;private Iterator<E> it;public ArrayDoubleEndStackIterator() {list = new ArrayList<>();for (int i = 0; i <= ltop; i++) {list.add(data[i]);}for (int i = rtop; i < data.length; i++) {list.add(data[i]);}it = list.iterator();}@Overridepublic boolean hasNext() {return it.hasNext();}@Overridepublic E next() {return it.next();}}
}

双端栈的扩容与缩容问题;

双端栈A中有下标0-5的6个元素,对其进行扩容;

对其扩容时候,先考虑左边,从原来双端栈A的左边原封不动直接进入双端栈B,此时与双端栈A的左指针相同,皆为下标2,此时双端栈B的前3个元素不动,下标为【0,ltop】。

其次考虑右边的情况,通过观察,发现index为5的元素对应到11,所以即为newLen-1,而先前的rtop从双端栈A的3变到了双端栈B的9,可以观察到9 = 12 - 3;此时rtop =  newLen -  size(1)

这时候原先双端栈A的右边完全到了双端栈B的左边,完成了对双端栈A的扩容问题。

关于栈的习题应用:

1.关于题解回文数;

给定一个字符串,判断是否该字符串是否是回文字符串,即"aba" 则为一个满足回文的条件;

public class JudgingPalindrome {public static void main(String[] args) {solution01();System.out.println(solution02());}//通过栈的思想private static void solution01() {String text = "上海自来水来自海上"; ArrayStack<Character> stack = new ArrayStack<>();//遍历栈中元素for (int i = 0; i < text.length(); i++) {//对于栈中元素是奇是偶进行判断if (text.length() % 2 == 1 && i == text.length() / 2) {continue;}char c = text.charAt(i);//栈空进栈,相同时候元素弹出,不同时候进栈,判断最后是否栈为空,为空则回文if (stack.isEmpty()) {stack.push(c);} else {if (c != stack.peek()) {stack.push(c);} else {stack.pop();}}}System.out.println(stack.isEmpty());}//通过双指针的思想private static boolean solution02() {String text = "上海自来水来自海上";//头指针int i = 0;//尾指针int j = text.length() - 1;//循环条件,头尾同时进行,首位匹配下一位,不同则返回false;while (true) {if (text.charAt(i) == text.charAt(j)) {i++;j--;} else {return false;}//尾指针要小于等于头指针if (j <= i) {return true;}}}
}

2.关于括号匹配问题

给定一些列括号‘(‘ ,’)’,‘【‘,’】’等,判断给定的括号串,是否完全匹配。如:“({()()})”;


//括号匹配
import java.util.HashMap;public class MatchBracket {public static void main(String[] args) {solution01();solution02();}//通过栈的思想解决private static void solution01() {String str = "{()[[()]]<>{}()<>}()";ArrayStack<Character> stack = new ArrayStack<>();//循环该数组下标,栈为空进栈for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);if (stack.isEmpty()) {stack.push(c);} else {//当前栈顶char top = stack.peek();//通过ascll码匹配当满足条件时候,弹栈,即完成匹配if (top - c == -1 || top - c == -2) {stack.pop();} else {stack.push(c);}}}//当stack为空时候说明括号完全匹配System.out.println(stack.isEmpty());}//通过HashMap实现private static void solution02() {String str = "{()[[()]]<{()>}()";//给定hashmap的键值对应关系HashMap<Character,Character> map = new HashMap<>();map.put('[',']');map.put('<','>');map.put('(',')');map.put('{','}');ArrayStack<Character> stack = new ArrayStack<>();//遍历和法1相同for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);if (stack.isEmpty()) {stack.push(c);} else {char top = stack.peek();//contains保证键值关系,包含时候,看c是否满足关系,满足时候弹栈,不满足继续入栈if (map.containsKey(top) && c == map.get(']')) {stack.pop();} else {stack.push(c);}}}System.out.println(stack.isEmpty());}
}

3.简单计算器的实现

给定(),+ - */四则运算,做出来一个简单的计算器 如(10+20/2*3)/2+8 = 28

3.1中缀表达式计算器

//中缀表达式计算器
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 num1if (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();}
}

3.2后缀表达式计算器

//后缀表达式的计算器
public class SuffixCalculator {public static void main(String[] args) {String infixExpression = "(10+20/2*3)/2+8";String suffixExpression = InfixToSuffix.infixToSuffix(infixExpression);int result = evaluateSuffix(suffixExpression);System.out.println(result);}private static int evaluateSuffix(String expression) {ArrayStack<Integer> stack = new ArrayStack<>();String[] tokens = expression.split(" ");for (String token : tokens) {if (token.length() == 0) {continue;}if (isNumber(token)) {stack.push(new Integer(token));} else {processAnOperator(stack,token);}}return stack.pop();}private static void processAnOperator(ArrayStack<Integer> stack, String token) {int num1 = stack.pop();int num2 = stack.pop();if (token.equals("+")) {stack.push(num2 + num1);} else if (token.equals("-")) {stack.push(num2 - num1);} else if (token.equals("*")) {stack.push(num2 * num1);} else if (token.equals("/")) {stack.push(num2 / num1);}}private static boolean isNumber(String token) {return token.matches("\\d+");}
}

3.3中缀转换后缀

//中缀表达式转后缀表达式
public class InfixToSuffix {public static void main(String[] args) {String expression = "(10+20/2*3)/2+8";expression = infixToSuffix(expression);System.out.println(expression);}private static String infixToSuffix(String expression) {//操作符的栈ArrayStack<String> opStack = new ArrayStack<>();//后缀表达式的线性表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();}
}

Java数据结构之栈详解相关推荐

  1. 数据结构-链栈详解(很朴实的那种)

    链栈的设计与运行 1.链栈 提起链栈,很容易就想到单链表,不过链栈确实可以看做是受限的单链表,因为只能在链表头部进行操作,所以在链栈中也不再附加头结点,栈顶指针就是链表的头指针. 老话一句,实践一遍, ...

  2. 【数据结构】栈详解——压栈/入栈 | 弹栈/出栈 | 获取栈顶元素

    栈 顺序栈 栈的定义 栈(stack)又名堆栈,它是一种运算受限的线性表.限定仅在表尾进行插入和删除操作的线性表.这一端被称为栈顶,相对地,把另一端称为栈底.向一个栈插入新元素又称作进栈.入栈或压栈, ...

  3. 【Java数据结构】泛型详解+图文,通配符上界、下界

    0. 泛型的本质 0. 泛型的目的 1. 泛型的语法 1.1 泛型的使用 2. 包装类 2.1 装箱和拆箱 2.2.1练习题 3 .泛型如何编译 4.泛型的上界 5. 通配符 5.1通配符上界 5.2 ...

  4. Java基础学习总结(58)——JAVA堆、栈详解

    关于堆栈的内容网上已经有很多资料了,这是我找的加上自己理解的一篇说明文:

  5. 蘑菇街2015校招 Java研发笔试题 详解,2015java

    蘑菇街2015校招 Java研发笔试题 详解,2015java 1. 对进程和线程描述正确的是( ) A.  父进程里的所有线程共享相同的地址空间,父进程的所有子进程共享相同的地址空间. B.  改变 ...

  6. Java JUC学习 - ConcurrentLinkedDeque 详解

    Java JUC学习 - ConcurrentLinkedDeque 详解 0x00 前言 如何实现并发程序,对于Java以及其他高级语言来说都是一件并不容易的事情.在大一上学期的时候,我们学习了链表 ...

  7. Java虚拟机(Jvm详解)

    Java虚拟机(Jvm详解) 总体知识点框架 1.运行时数据区域 线程私有的: 程序计数器 虚拟机栈 本地方法栈 线程共享的: 堆 方法区 直接内存 (非运行时数据区的一部分) Java 虚拟机规范对 ...

  8. Java 并发之 AQS 详解(上)

    Java 并发之 AQS 详解 前言 Java SDK 为什么要设计 Lock 死锁问题 synchronized 的局限性 显式锁 Lock Lock 使用范式 Lock 是怎样起到锁的作用呢? 队 ...

  9. Java单元测试之JUnit4详解

    2019独角兽企业重金招聘Python工程师标准>>> Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法.目前支持的主要注解有: @B ...

最新文章

  1. LeetCode简单题之换酒问题
  2. ViewPager 实现界面加载不同的数据
  3. 本硕非科班,单模型获得亚军!
  4. B1013 数素数(20分)
  5. iOS之深入解析消息转发objc_msgSend的应用场景
  6. Echarts API说明文档
  7. jfinal使用shiro注解大体流程
  8. C++链表插入节点函数为什么要传递头节点的二维指针
  9. chrome浏览器ios版本迎来“信用卡扫描器”代码
  10. 最详细的YOLO论文笔记
  11. nginx反向代理docker registry报”blob upload unknown解决办法
  12. 会员积分消费系统 php,会员消费管理系统充值营销系统会员积分消费系统.net源码...
  13. TeeChart Pro ActiveX教程(十九):TeeChart工具集(六)
  14. ABP vNext 缓存使用
  15. Python基础知识点回顾
  16. AE效果器(Effect)开发
  17. springboot使用FileAlterationMonitor完成对指定文件夹下面指定文件的动态监控
  18. 自然语言处理从零到入门 BERT
  19. 谁说国内无RISC-V开源核——您还不知蜂鸟E200?
  20. git Cherry-pick Failed your local changes would be overwritten by cherry-pick. hint: commit your

热门文章

  1. 达人评测 i5 13400F对比i5 12490F选哪个好
  2. GHOST系统封装教程 系统封装工具 XP系统封装(一)
  3. 【操作系统-Windows】浅析360带来的蓝屏问题
  4. JavaSE学习总结(八)常用类(上)Object类==与equals方法的区别浅克隆的特点Scanner类String类String两种创建对象方式的区别String类的各种功能
  5. 轻松解决在线QQ客服未启用状态
  6. 存储设备映射Linux服务器,在linux和Windows下配置HP FC存储设备多路径驱动
  7. 【杂谈】ChatGPT是否可以取代人类的工作
  8. C# FileSystemWatcher文件监控
  9. WEB数据库管理平台kb-dms:数据源配置【五】
  10. 未来计算机一种新兴的计算机类型,酷毙了!10款神奇的未来计算机