week07_day01_自己实现LinkedList、MyStack

2023-12-03 23:58

本文主要是介绍week07_day01_自己实现LinkedList、MyStack,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

head 和 tail 是两个哨兵结点,不存储值。
在这里插入图片描述
在这里插入图片描述
MyList和MyIterator接口的代码和上节课一模一样

MyList:

package com.cskaoyan.list;/*** @author shihao* @create 2020-05-15 17:28*///想让MyArrayList和LinkedList也可以实现自己的foreach循环,
// 就得让MyList实现接口Iterable,表示有迭代的能力
public interface MyList<E> extends Iterable<E> {boolean add(E e);void add(int index, E e);void clear();boolean contains(Object obj);E get(int index);int indexOf(Object obj);boolean isEmpty();//MyIterator模仿的是listIterator//应当实现一个迭代器,对MyList进行遍历MyIterator<E> iterator();MyIterator<E> iterator(int index);int lastIndexOf(Object obj);E remove(int index);boolean remove(Object obj);E set(int index, E e);int size();
}

MyIterator:

package com.cskaoyan.list;/*** @author shihao* @create 2020-05-16 8:09*/import java.util.Iterator;//MyIterator模仿的是listIterator
//MyIterator
public interface MyIterator<E> extends Iterator<E> {boolean hasNext();boolean hasPrevious();E next();E previous();int nextIndex();int previousIndex();void add(E e);void remove();void set(E e);
}

MyLinkedList:

package com.cskaoyan.list;import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.NoSuchElementException;/*** @author shihao* @create 2020-05-16 21:16*/
public class MyLinkedList<E> implements MyList<E> {//属性//MyLinkedList底层是一个双端队列private Node head;private Node tail;private int size;private int modCount;//不需要默认容量和最大容量//Node不依赖于外部类对象而存在,所以将Node设置为static//当然,加上static后就不能将value设置为E类型,//因为泛型是创建对象的时候才把泛型参数传入进来的,泛型依赖于对象存在private static class Node {Node prev;Object value;Node next;public Node(Object value) {this.value = value;}public Node(Node prev, Object value, Node next) {this.prev = prev;this.value = value;this.next = next;}}//构造方法//创建一个空链表public MyLinkedList() {head = new Node(null);tail = new Node(head, null, null);head.next = tail;}//应当在head之前和tail之后设置哨兵结点//方法/*** 在线性表最后添加元素** @param e 待添加的元素* @return 如果添加成功返回true*/@Overridepublic boolean add(E e) {add(size, e);return true;}/*** 在线性表指定位置添加元素** @param index 指定索引位置* @param e     待添加的元素*/@Overridepublic void add(int index, E e) {checkIndexForAdd(index);  //index的范围:[0,size]//需要考虑一种特殊情况:index == size时if (index == size) {Node nodeToAdd = new Node(tail.prev, e, tail);tail.prev.next = nodeToAdd;tail.prev = nodeToAdd;} else {//获取索引为index的结点Node node = getNode(index);  //index的范围:[0,size-1]//在node前面插入新节点Node nodeToAdd = new Node(node.prev, e, node);node.prev.next = nodeToAdd;node.prev = nodeToAdd;}size++;modCount++;}/*** 获取index位置的结点** @param index* @return index位置的结点* <p>* A --> B --> C  size=3* A --> B --> C --> D  size=4*/private Node getNode(int index) {if (index * 2 < size) {Node x = head.next;//x最终指向索引为index的结点for (int i = 0; i < index; i++) {x = x.next;}return x;} else {Node x = tail.prev;//x最终指向索引为index的结点for (int i = size - 1; i > index; i++) {x = x.prev;}return x;}}private void checkIndexForAdd(int index) {if (index < 0 || index > size) {throw new IndexOutOfBoundsException("index = " + index + ", size = " + size);}}/*** 清空链表中所有元素*/@Overridepublic void clear() {head.next = tail;tail.prev = head;size = 0;modCount++;}/*** 判断线性表中是否有与指定元素相等的元素** @param obj 指定对象* @return 如果存在这样额元素返回true,否则返回false*/@Overridepublic boolean contains(Object obj) {return indexOf(obj) != -1;}/*** 获取指定索引位置的元素** @param index 指定索引位置* @return 指定索引位置的元素*/@Override@SuppressWarnings("unchecked")public E get(int index) {checkIndex(index);return (E) getNode(index).value;}private void checkIndex(int index) {if (index < 0 || index > size - 1) {throw new IndexOutOfBoundsException("index = " + index + ", size = " + size);}}/*** 获取线性表中第一个与指定对象相等的元素** @param obj 指定对象* @return 第一个和指定对象相等的元素的索引,如果不存在这样的索引返回-1*/@Overridepublic int indexOf(Object obj) {if (obj == null) {Node x = head.next;for (int i = 0; i < size; i++) {if (x.value == null) return i;x = x.next;}} else {Node x = head.next;for (int i = 0; i < size; i++) {if (obj.equals(x.value)) return i;x = x.next;}}return -1;}/*** 判断线性表是否为空** @return 为空返回true,否则返回false*/@Overridepublic boolean isEmpty() {return size == 0;}/*** 获取最后一个与指定对象相等元素的索引** @param obj 指定对象* @return 最后一个与指定对象相等元素的索引,如果不存在这样的元素返回-1*/@Overridepublic int lastIndexOf(Object obj) {if (obj == null) {Node x = tail.prev;for (int i = size - 1; i >= 0; i--) {if (x.value == null) return i;x = x.prev;}} else {Node x = tail.prev;for (int i = size - 1; i >= 0; i--) {if (obj.equals(x.value)) return i;x = x.prev;}}return -1;}/*** 删除指定索引位置的元素,并把被删除的元素返回** @param index 索引* @return 被删除的元素*/@Override@SuppressWarnings("unchecked")public E remove(int index) {checkIndex(index);Node node = getNode(index);node.prev.next = node.next;node.next.prev = node.prev;size--;modCount++;return (E) node.value;}@Overridepublic boolean remove(Object obj) {//不要用以下写法,因为indexOf会遍历一遍链表,remove(index)也会//遍历一遍链表,其实整个方法只需遍历一次链表即可,我们却遍历了两次
/*        int index = indexOf(obj);if (index == -1) return false;remove(index);return true;*///只遍历一次if (obj == null) {Node x = head.next;for (int i = 0; i < size; i++) {if (x.value == null) {//删除x结点x.prev.next = x.next;x.next.prev = x.prev;size--;modCount++;return true;}x = x.next;}} else {Node x = head.next;for (int i = 0; i < size; i++) {if (obj.equals(x.value)) {//删除x结点x.prev.next = x.next;x.next.prev = x.prev;size--;modCount++;return true;}x = x.next;}}return false;}/*** 将索引位置元素替换为新值** @param index 索引* @param e     新值* @return 旧值*/@Overridepublic E set(int index, E e) {checkIndex(index);Node node = getNode(index);E retValue = (E) node.value;node.value = e;return retValue;}/*** 获取线性表中元素的个数** @return 元素的个数*/@Overridepublic int size() {return size;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("[");Node x = head.next;while (x != tail) {sb.append(x.value).append("-->");x = x.next;}if (size != 0) {sb.delete(sb.length() - 3, sb.length());}return sb.append("]").toString();}/*** 获取迭代器,光标后面的元素的索引为0** @return 迭代器*/@Overridepublic MyIterator<E> iterator() {return new Itr();}/*** 获取迭代器,光标后面的元素的索引为index** @param index 光标后面的元素的索引* @return 迭代器*/@Overridepublic MyIterator<E> iterator(int index) {checkIndexForAdd(index);return new Itr(index);}private class Itr implements MyIterator<E> {//属性int cursor;  //光标后面元素的索引Node node;  //光标后面的结点int expModCount = modCount;  //期待被修改的次数//lastRet表示上一次返回的结点Node lastRet = null;  //null表示最近没有返回结点或最近返回的结点已失效//构造方法//无需加public,因为外界不可能通过构造方法访问到Itr内部类Itr() {node = head.next;}Itr(int index) {cursor = index;if (index == size) {node = tail;} else {node = getNode(index);}}//方法/*** 判断光标后面是否还有元素** @return 如果有元素返回true,没有元素返回false*/@Overridepublic boolean hasNext() {return cursor != size;}/*** 判断光标前面是否还有元素** @return 如果有元素返回true,没有元素返回false*/@Overridepublic boolean hasPrevious() {return cursor != 0;}/*** 将光标往后移动一个元素,并把被光标越过的元素返回** @return 被光标越过的元素*/@Override@SuppressWarnings("unchecked")public E next() {checkConModException();if (!hasNext()) {throw new NoSuchElementException();}cursor++;lastRet = node;node = node.next;return (E) lastRet.value;}private void checkConModException() {if (expModCount != modCount) {throw new ConcurrentModificationException();}}/*** 将光标往前移动一个位置,并把被光标越过的元素返回** @return 被光标越过的元素*/@Override@SuppressWarnings("unchecked")public E previous() {checkConModException();if (!hasPrevious()) {throw new NoSuchElementException();}cursor--;node = node.prev;lastRet = node;return (E) lastRet.value;}/*** 获取光标后面元素的索引** @return*/@Overridepublic int nextIndex() {return cursor;}/*** 获取光标前面元素的索引** @return*/@Overridepublic int previousIndex() {return cursor - 1;}/*** 在光标后面添加元素** @param e 待添加的元素*/@Overridepublic void add(E e) {//不用这句代码,add(cursor,e)的时间复杂度为O(n)//MyLinkedList.this.add(cursor,e);//完全可以在O(1)的时间复杂度下完成add操作Node nodeToAdd = new Node(node.prev, e, node);node.prev.next = nodeToAdd;node.prev = nodeToAdd;size++;cursor++;lastRet = null;  //添加完元素后让最近返回的元素失效//如果没有这句代码,本迭代器修改之后,其他迭代器是感知不到修改的//也就是说理应报并发修改异常但却没报//解释:expModCount = ++modCount;后,本迭代器的expModCount和外部类中的modCount值相同//而在本迭代器创立之前的其他迭代器的expModCount可是比现在的++modCount小1,既然不相等//在执行it.next()时,调用 checkConModException();就会报并发修改异常expModCount = ++modCount;}/*** 删除最近返回的元素*/@Overridepublic void remove() {checkConModException();//当最近返回的元素失效或者最近没有返回的元素时if (lastRet == null) {throw new IllegalStateException();}//删除nodelastRet.prev.next = lastRet.next;lastRet.next.prev = lastRet.prev;//4个属性值的变化expModCount = ++modCount;size--;//如果是逆向遍历,node和lastRet是相等的if (lastRet == node) {node = node.next;} else {  //如果是正向遍历,node和lastRet是不相等的cursor--;}lastRet = null;}/*** 替换最近返回的元素** @param e 替换后的值*/@Overridepublic void set(E e) {checkConModException();if (lastRet == null) {throw new IllegalStateException();}lastRet.value = e;lastRet = null;}}public static void main(String[] args) {MyLinkedList<String> list = new MyLinkedList<>();System.out.println(list);list.add("hello");list.add("world");list.add("java");System.out.println(list);// void add(int index, E e)// list.add(0, "A");// list.add(1, "A");// list.add(list.size(), "A");// list.add(list.size() + 1, "A");// list.add(-1, "A");// System.out.println(list);// void clear(), int size(), boolean isEmpty()/*System.out.println(list);System.out.println(list.size());System.out.println(list.isEmpty());list.clear();System.out.println(list);System.out.println(list.size());System.out.println(list.isEmpty());*/// boolean contains(Object obj)/*System.out.println(list.contains("java")); //trueSystem.out.println(list.contains("wuhan")); //falseSystem.out.println(list.contains(null));//falselist.add(null);System.out.println(list.contains(null));//true*/// int indexOf(Object obj)
/*        list.add("hello");System.out.println(list);System.out.println(list.indexOf("hello"));System.out.println(list.indexOf(null));list.add(0, null);list.add(null);System.out.println(list);System.out.println(list.indexOf(null));*/// int lastIndexOf(Object obj)
/*        list.add("hello");System.out.println(list);System.out.println(list.lastIndexOf("hello"));System.out.println(list.lastIndexOf(null));list.add(0, null);list.add(null);System.out.println(list);System.out.println(list.lastIndexOf(null));*/// E get(int index)// System.out.println(list.get(1));// System.out.println(list.get(-1));// System.out.println(list.get(list.size()));// E remove(index)// System.out.println(list.remove(1));// System.out.println(list.remove(-1));// System.out.println(list.remove(list.size()));// System.out.println(list);// boolean remove(Object)/*list.add("hello");System.out.println(list.remove("hello"));System.out.println(list);System.out.println(list.remove(null));System.out.println(list);list.add(0, null);list.add(null);System.out.println(list);System.out.println(list.remove(null));System.out.println(list);*/// E set(int index, E e)// System.out.println(list.set(2, "JAVA"));// System.out.println(list.set(-1, "JAVA"));// System.out.println(list.set(list.size(), "JAVA"));// System.out.println(list);/******************************************************                 Iterator*****************************************************/
//        MyLinkedList<String> list = new MyLinkedList<>();
//        list.add("hello");
//        list.add("world");
//        list.add("java");// boolean hasPrevious(), boolean hasNext()// MyIterator<String> it = list.iterator();// MyIterator<String> it = list.iterator(list.size());// MyIterator<String> it = list.iterator(1);// System.out.println(it.hasPrevious());// System.out.println(it.hasNext());// E previous(), E next()/*MyIterator<String> it = list.iterator();System.out.println(it.next());System.out.println(it.next());System.out.println(it.next());System.out.println(it.next());*//*        MyIterator<String> it = list.iterator(list.size());System.out.println(it.previous());System.out.println(it.previous());System.out.println(it.previous());System.out.println(it.previous());*/// int previousIndex()  int nextIndex()/*MyIterator<String> it = list.iterator();System.out.println(it.previousIndex());System.out.println(it.nextIndex());it.next();System.out.println(it.previousIndex());System.out.println(it.nextIndex());it.next();System.out.println(it.previousIndex());System.out.println(it.nextIndex());it.next();System.out.println(it.previousIndex());System.out.println(it.nextIndex());*/// void add(E e)/*MyIterator<String> it = list.iterator(1);it.add("A");it.add("B");it.add("C");System.out.println(list);System.out.println(it.next());*/// 在"hello"后面添加元素//测试两个迭代器的增加和遍历操作
//        MyIterator<String> iterator = list.iterator();
//        for (MyIterator<String> it = list.iterator(); it.hasNext(); ) {
//            String s = it.next();
//            if ("hello".equals(s)) {
//                int index = it.nextIndex();
//                it.add("A");
//            }
//        }
//        System.out.println(list);
//        //演示Itr中的add方法中的 expModCount = ++modCount; 这句代码的作用
//        while (iterator.hasNext()) {
//            String s = iterator.next();
//            System.out.println(s);
//        }// void remove()/*MyIterator<String> it = list.iterator();// it.remove();it.next();it.remove();System.out.println(list);*/
/*         MyIterator<String> it = list.iterator(list.size());it.previous();//it.add("HELLO");//add一次后lastRet所代表的最近返回的元素就失效了it.remove();System.out.println(list);//remove一次后lastRet所代表的最近返回的元素就失效了//it.remove();*/// 删除"hello"/*for(MyIterator<String> it = list.iterator(); it.hasNext(); ) {String s = it.next();if ("hello".equals(s)) {int index = it.previousIndex();list.remove(index);}}System.out.println(list);*//*        MyIterator<String> it = list.iterator();// it.set("HELLO");it.next();it.set("HELLO");// it.set("HeLLo");System.out.println(list);*//*MyIterator<String> it = list.iterator(list.size());it.previous();it.set("JAVA");System.out.println(list);*/}}

栈的非顺序映象(链栈):
在这里插入图片描述
····················································································································································································································

栈的API:

入栈 (push):在栈顶添加元素,O(1)
出栈 (pop):从栈顶删除元素,O(1)
查看栈顶元素 (peek):访问栈顶元素但不弹出,O(1)
判空 (isEmpty):判断栈是否为空, 方便遍历,O(1)

栈的非顺序映象(链栈):

package com.cskaoyan.stack;import java.util.EmptyStackException;/*** @author shihao* @create 2020-05-18 22:37* <p>* 栈的非顺序映象* API:* void push(E e)* E pop()* E peek()* boolean isEmpty()*/
public class MyStack<E> {//使用单链表作为底层的数据结构private static class Node {Object value;Node next;public Node(Object value) {this.value = value;}public Node(Object value, Node next) {this.value = value;this.next = next;}}//属性private Node top;//构造方法//默认会实现无参构造方法,top会置为null//方法/*** 入栈,即在栈顶添加元素** @param e 待添加的元素*/public void push(E e) {top = new Node(e, top);}/*** 出栈,即删除栈顶元素* @return 删除掉的元素*/@SuppressWarnings("unchecked")public E pop(){if (this.isEmpty()){throw new EmptyStackException();}E removeValue = (E) top.value;top = top.next;return removeValue;}/*** 查看栈顶元素* @return 栈顶元素*/@SuppressWarnings("unchecked")public E peek(){if(this.isEmpty()){throw new EmptyStackException();}return (E) top.value;}/*** 判断栈是否为空** @return 栈空返回true,否则返回false*/public boolean isEmpty() {return top == null;}}

栈的顺序映象(顺序栈):

package com.cskaoyan.stack;import java.util.EmptyStackException;/*** @author shihao* @create 2020-05-19 7:26* <p>* 栈的顺序映象* API:* void push(E e)* E pop()* E peek()* boolean isEmpty()*/
public class MyStack02<E> {//栈的默认容量private static final int DEFAULT_CAPACITY = 10;//栈的最大容量private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8;//属性private Object[] elements;private int top = -1;//构造方法public MyStack02() {elements = new Object[DEFAULT_CAPACITY];}public MyStack02(int capacity) {if (capacity <= 0 || capacity > MAX_CAPACITY) {throw new IllegalArgumentException("capacity = " + capacity);}elements = new Object[capacity];}//方法/*** 入栈,即在栈顶添加元素** @param e 待添加的元素*/public void push(E e) {if (top == (elements.length - 1)) {//扩容int newLength = calculateCapacity();grow(newLength);}top++;elements[top] = e;}private void grow(int newCapacity) {//数组大小是不可变的,应当新建一个更大的数组,将原数组的元素传递给它Object[] newArr = new Object[newCapacity];for (int i = 0; i < elements.length; i++) {newArr[i] = elements[i];}//elements指向新数组elements = newArr;}private int calculateCapacity() {if (elements.length == MAX_CAPACITY) {throw new RuntimeException("Stack is too large!");}int newCapacity = elements.length + elements.length >> 1;if (newCapacity > MAX_CAPACITY || newCapacity < 0) {newCapacity = MAX_CAPACITY;}return newCapacity;}/*** 出栈,即删除栈顶元素** @return 删除掉的元素*/@SuppressWarnings("unchecked")public E pop() {if (top == -1) {throw new EmptyStackException();}E retValue = (E) elements[top];elements[top] = null;top--;return retValue;}/*** 查看栈顶元素** @return 栈顶元素*/@SuppressWarnings("unchecked")public E peek() {if (top == -1) {throw new EmptyStackException();}return (E) elements[top];}/*** 判断栈是否为空** @return 栈空返回true,否则返回false*/public boolean isEmpty() {return top == -1;}}

练习题:反转字符串(要求用栈实现)
输入:“ABC”
输出:“CBA”
思路:
a.遍历字符串,获取每一个字符。charAt(int index)
b.将字符入栈
c.依次将字符出栈,并拼接

public class Demo01 {public static void main(String[] args) {String s = "123456";System.out.println(reverse(s));}private static String reverse(String original) {MyStack02<Character> myStack = new MyStack02<>();for (int i = 0; i < original.length(); i++) {char c = original.charAt(i);myStack.push(c);}StringBuilder sb = new StringBuilder();while (!myStack.isEmpty()) {sb.append(myStack.pop());}return sb.toString();}
}

应用场景:

  1. 函数调用栈:如在主方法中调用一个fun方法,会为fun方法创建一个栈帧,而一定是fun方法先执行结束的,然后主方法再执行结束。先调用的方法(主方法)后执行完,后调用的方法(fun方法)先执行完。这正好满足FILO特性。

  2. 括号匹配问题
    在这里插入图片描述
    老师代码:

public class StackDemo2 {public static void main(String[] args) {// String original = "([{}])";// String original = "()[]{";String original = "public static void main(String[ args) {System.out.println(bracketMatched(original));}";System.out.println(bracketMatched(original));}/*时间复杂度:O(n)空间复杂度:O(a):字符串中括号的个数*/public static boolean bracketMatched(String original) {Deque<Character> stack = new LinkedList<>();// 遍历字符串, 获取每一个字符for (int i = 0; i < original.length(); i++) {char c = original.charAt(i);if (c == '(') stack.push(')');if (c == '[') stack.push(']');if (c == '{') stack.push('}');if (c == ')' || c == ']' || c== '}') {if (stack.isEmpty()) return false;if (c != stack.pop()) return false;}}// 遍历结束后return stack.isEmpty();}
}

我的代码(天勤、LeetCode之有效的括号):

class Solution {public boolean isValid(String s) {char[] stack=new char[s.length()];int top=-1;for(int i=0;i<s.length();i++){char ch=s.charAt(i);if(ch=='('||ch=='['||ch=='{')stack[++top]=ch;else{if(top==-1)return false;       //缺左括号char left=stack[top--];if(!isMathced(left,ch))return false;       //左右括号不匹配}}if(top!=-1)return false;     //缺右括号return true;}private boolean isMathced(char left,char right){if(left=='('&&right==')')return true;else if(left=='['&&right==']')return true;else if(left=='{'&&right=='}')return true;elsereturn false;}
}
  1. 编译器利用栈实现表达式求值
    在这里插入图片描述
    具体代码看之前天勤笔记。

  2. 浏览器的前进后退功能
    在这里插入图片描述

  3. 利用栈实现 DFS

这篇关于week07_day01_自己实现LinkedList、MyStack的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/451344

相关文章

Python实现Word转PDF全攻略(从入门到实战)

《Python实现Word转PDF全攻略(从入门到实战)》在数字化办公场景中,Word文档的跨平台兼容性始终是个难题,而PDF格式凭借所见即所得的特性,已成为文档分发和归档的标准格式,下面小编就来和大... 目录一、为什么需要python处理Word转PDF?二、主流转换方案对比三、五套实战方案详解方案1:

SpringBoot集成EasyExcel实现百万级别的数据导入导出实践指南

《SpringBoot集成EasyExcel实现百万级别的数据导入导出实践指南》本文将基于开源项目springboot-easyexcel-batch进行解析与扩展,手把手教大家如何在SpringBo... 目录项目结构概览核心依赖百万级导出实战场景核心代码效果百万级导入实战场景监听器和Service(核心

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

基于Python Playwright进行前端性能测试的脚本实现

《基于PythonPlaywright进行前端性能测试的脚本实现》在当今Web应用开发中,性能优化是提升用户体验的关键因素之一,本文将介绍如何使用Playwright构建一个自动化性能测试工具,希望... 目录引言工具概述整体架构核心实现解析1. 浏览器初始化2. 性能数据收集3. 资源分析4. 关键性能指

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的