【数据结构】LinkedList ------ java实现

  知识框架图:

  LinkedList是一种常用的数据结构。底层是一个双向链表。每个节点包含数据以及指向前一个节点和后一个节点的引用。

   一:LinkedList的使用

   1.1 LinkedList的构造方法

方法 解释
LinkedList() 无参构造
public LinkedList(Collection<? extends E> c) 使用其他集合容器中元素构造List

  代码示例: 

public static void main(String[] args) {
// 构造一个空的LinkedList
List<Integer> list1 = new LinkedList<>();
List<String> list2 = new ArrayList<>();list2.add("三国演义");
list2.add("西游记");
list2.add("水浒传");// 使用ArrayList构造LinkedList
List<String> list3 = new LinkedList<>(list2);
}

  1.2 LinkedList的常用方法

方法 解释
boolean add (E e) 尾插 e
void add (int index, E element)将 e 插入到 index 位置
boolean addAll (Collection<? extends E> c)尾插 c 中的元素
E remove (int index) 删除 index 位置元素
boolean remove (Object o)删除遇到的第一个 o
E get (int index)获取下标 index 位置元素
E set (int index, E element)将下标 index 位置元素设置为 element
void clear () 清空
boolean contains (Object o) 判断 o 是否在线性表中
int indexOf (Object o) 返回第一个 o 所在下标
int lastIndexOf (Object o)返回最后一个 o 的下标
List<E> subList (int fromIndex, int toIndex)截取部分 list

  部分方法代码示例:

public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
list.add(1); // add(elem): 表示尾插
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
System.out.println(list.size());
System.out.println(list);
// 在起始位置插入0
list.add(0, 0); // add(index, elem): 在index位置插入元素elem
System.out.println(list);
list.remove(); // remove(): 删除第一个元素,内部调用的是removeFirst()
list.removeFirst(); // removeFirst(): 删除第一个元素
list.removeLast(); // removeLast(): 删除最后元素
list.remove(1); // remove(index): 删除index位置的元素
System.out.println(list);
// contains(elem): 检测elem元素是否存在,如果存在返回true,否则返回false
if(!list.contains(1)){
list.add(0, 1);
}list.add(1);
System.out.println(list);
System.out.println(list.indexOf(1)); // indexOf(elem): 从前往后找到第一个elem的位置
System.out.println(list.lastIndexOf(1)); // lastIndexOf(elem): 从后往前找第一个1的位置
int elem = list.get(0); // get(index): 获取指定位置元素
list.set(0, 100); // set(index, elem): 将index位置的元素设置为elem
System.out.println(list);
// subList(from, to): 用list中[from, to)之间的元素构造一个新的LinkedList返回
List<Integer> copy = list.subList(0, 3); 
System.out.println(list);
System.out.println(copy);
list.clear(); // 将list中元素清空
System.out.println(list.size());
}

  1.3 LinkedList的遍历 

  1.使用普通 for 循环遍历

//由于LinkedList不能像数组那样通过索引直接快速访问元素,使用普通 for 循环遍历需要借助size()方法和 
//get(int index)方法来逐个获取元素。这种方式效率较低,不推荐在频繁遍历的场景中使用。for (int i = 0; i < list.size(); i++) {String element = list.get(i);System.out.println(element);
}

  2.使用增强型 for 循环遍历

//增强for循环可以简洁地遍历集合中的元素。
for (String element : list) {System.out.println(element);
}

  3. 使用迭代器(Iterator)遍历

//1.使用迭代器的hasNext和next方法进行遍历,避免在遍历过程中频繁调用size方法
//或通过索引访问元素。这样可以提高遍历的效率,特别是在处理大型链表时。//2.在遍历过程中尽量避免对链表进行修改操作,因为这可能会导致迭代器失效,需要重新获取迭代器。
//如果必须在遍历过程中进行修改,可以使用迭代器的remove方法来安全地删除元素。LinkedList<String> list = new LinkedList<>();
list.add("计算机科学与技术");
list.add("软件工程");
list.add("人工智能");//1.获取迭代器:可以通过LinkedList的iterator()方法获取一个Iterator对象。
Iterator<String> iterator = list.iterator();//2.使用迭代器遍历:通过hasNext()方法判断是否还有下一个元素,使用next()方法获取下一个元素。
while (iterator.hasNext()) {String element = iterator.next();System.out.println(element);
}


  4. 从链表尾部向头部遍历


LinkedList<String> list = new LinkedList<>();
list.add("计算机科学与技术");
list.add("软件工程");
list.add("人工智能");//1.获取列表迭代器并指向尾部:可以使用listIterator(int index)方法获取一个ListIterator对象,
//并将其初始位置设置为链表的尾部。
ListIterator<String> listIterator = list.listIterator(list.size());//2.向头部遍历:使用hasPrevious()方法判断是否还有前一个元素,使用previous()方法获取前一个元素。
while (listIterator.hasPrevious()) {String element = listIterator.previous();System.out.println(element);
}

   二:使用案例

  2.1实现队列和栈数据结构

  1. 队列(Queue):

  • LinkedList 可以很方便地用来实现队列。在队列中,元素遵循先进先出(FIFO)的原则。可以利用 LinkedList 的 addLast 方法在队尾添加元素,使用 removeFirst 方法在队首取出元素。

  • 例如:在一个任务调度系统中,可以使用队列来管理待执行的任务。新任务添加到队尾,执行引擎从队首获取任务并执行。
 

  代码示例:

import java.util.LinkedList;public class TaskQueue {private LinkedList<String> queue = new LinkedList<>();public void addTask(String task) {queue.addLast(task);}public String getNextTask() {return queue.removeFirst();}public static void main(String[] args) {TaskQueue taskQueue = new TaskQueue();taskQueue.addTask("Task 1");taskQueue.addTask("Task 2");System.out.println(taskQueue.getNextTask()); // 输出:Task 1System.out.println(taskQueue.getNextTask()); // 输出:Task 2}
}

  2. 栈(Stack):

  • LinkedList 也可以用于实现栈。在栈中,元素遵循先进后出(LIFO)的原则。可以使用 addFirst 方法将元素压入栈顶,使用 removeFirst 方法弹出栈顶元素。

  • 例如:在表达式求值、函数调用栈等场景中可以使用栈。
 

import java.util.LinkedList;public class StackExample {private LinkedList<String> stack = new LinkedList<>();public void push(String item) {stack.addFirst(item);}public String pop() {return stack.removeFirst();}public static void main(String[] args) {StackExample stack = new StackExample();stack.push("Item 1");stack.push("Item 2");System.out.println(stack.pop()); // 输出:Item 2System.out.println(stack.pop()); // 输出:Item 1}
}

  2.2. 频繁插入和删除的场景

  1. 日志记录系统:

  • 在一个日志记录系统中,新的日志条目不断产生并需要添加到日志列表中。同时,可能需要根据时间范围或其他条件删除一些旧的日志条目。由于 LinkedList 在插入和删除操作上的高效性,特别是在列表中间进行插入和删除时,非常适合这种场景。

  • 代码示例:

import java.util.LinkedList;public class LoggingSystem {private LinkedList<String> logs = new LinkedList<>();public void addLog(String logEntry) {logs.add(logEntry);}public void removeOldLogs(int daysAgo) {// 假设日志中有时间戳,可以根据时间戳删除超过指定天数的日志// 这里只是一个简单的示例,实际实现可能更复杂for (String log : logs) {// 根据条件判断是否删除日志}}public static void main(String[] args) {LoggingSystem loggingSystem = new LoggingSystem();loggingSystem.addLog("Log entry 1");loggingSystem.addLog("Log entry 2");// 后续可以根据需要添加和删除日志}
}

  2. 实时消息处理:

  • 在一个实时消息处理系统中,新的消息不断到来需要添加到消息队列中,同时已处理的消息可以从队列中删除。LinkedList 的高效插入和删除操作可以满足这种实时性要求。

  • 代码示例:

import java.util.LinkedList;public class MessageProcessingSystem {private LinkedList<String> messages = new LinkedList<>();public void addMessage(String message) {messages.add(message);}public String processNextMessage() {return messages.removeFirst();}public static void main(String[] args) {MessageProcessingSystem messageSystem = new MessageProcessingSystem();messageSystem.addMessage("Message 1");messageSystem.addMessage("Message 2");System.out.println(messageSystem.processNextMessage()); // 输出:Message 1System.out.println(messageSystem.processNextMessage()); // 输出:Message 2}
}

  三:LinkedList源码分析:

  3.1 主要成员变量

• size:表示链表中元素的个数。

• first:指向链表的第一个节点。

• last:指向链表的最后一个节点。

  3.2 内部节点类

• item:存储节点中的元素。

• next:指向下一个节点的引用。

• prev:指向前一个节点的引用。

  3.3 构造方法

   默认构造方法:创建一个空的链表。

   包含集合参数的构造方法:可以从另一个集合创建LinkedList,将集合中的元素依次添加到链表中。

  3.4添加元素方法

1. add(E e):在链表末尾添加元素。

    内部调用linkLast方法,将新元素作为最后一个节点添加到链表中。

2. add(int index, E element):在指定位置插入元素。

    首先检查索引是否合法,然后根据索引位置决定是在末尾添加(调用linkLast)还是在指定位置插入(调用linkBefore)。

  3.5 删除元素方法

 1. remove(int index): 删除指定位置的元素。

首先检查索引是否合法,然后调用unlink方法删除指定节点。 


public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
}
   E unlink(Node<E> x) {
    // assert x!= null;
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;

    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;
    return element;
}


2. remove(Object o):删除指定的元素。

遍历链表找到指定元素的节点,然后调用unlink方法删除该节点。


public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x!= null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x!= null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

  同理,其他的方法都可以通过源码阅读知道底层是怎么去实现的。

  四:模拟实现LinkedList

public class MyLinkedList {static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;//标记双向链表的头部public ListNode tail;//标记双向链表的尾部/*** 打印双向链表的每个节点 的值*/public void display() {ListNode cur = this.head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}//得到链表的长度public int size() {int count = 0;ListNode cur = this.head;while (cur != null) {cur = cur.next;count++;}return count;}//查找是否包含关键字key是否在单链表当中public boolean contains(int key) {ListNode cur = this.head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}public void addFirst(int data) {ListNode node = new ListNode(data);if (this.head == null) {this.head = node;this.tail = node;} else {node.next = this.head;this.head.prev = node;head = node;}}//尾插法public void addLast(int data) {ListNode node = new ListNode(data);if (this.head == null) {this.head = node;this.tail = node;} else {tail.next = node;node.prev = tail;tail = node;}}//任意位置插入,第一个数据节点为0号下标public void addIndex(int index, int data) {//1、判断Index位置的合法性if (index < 0 || index > size()) {throw new IndexWrongFulException("index位置不合法!");}//2、判断特殊位置,头插 和 尾插if (index == 0) {addFirst(data);return;}if (index == size()) {addLast(data);return;}//3、找到index位置节点的地址ListNode cur = findIndexListNode(index);//4、修改4个指向ListNode node = new ListNode(data);node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;}private ListNode findIndexListNode(int index) {ListNode cur = head;while (index != 0) {cur = cur.next;index--;}return cur;}//删除第一次出现关键字为key的节点public void remove(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {if (cur == head) {head = head.next;if (head != null) {head.prev = null;} else {tail = null;}} else {cur.prev.next = cur.next;if (cur.next != null) {cur.next.prev = cur.prev;} else {this.tail = cur.prev;}}return;}cur = cur.next;}}//删除所有值为key的节点public void removeAllKey(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {if (cur == head) {head = head.next;if (head != null) {head.prev = null;} else {tail = null;}} else {cur.prev.next = cur.next;if (cur.next != null) {cur.next.prev = cur.prev;} else {this.tail = cur.prev;}}}cur = cur.next;}}public void clear() {ListNode cur = head;while (cur != null) {ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}head = null;tail = null;}
}

  注意:上述代码中,只是简单模拟一下LinkedList中常用方法的实现逻辑,用的是基本数据类型,并没有像源码那样使用泛型,改成泛型更加通用,因为节点中的数据可能是引用数据类型或者自定义类型 。

  五:LinkedList细节

  5.1 插入和删除操作

  • LinkedList在进行插入和删除操作时非常高效,尤其是在链表中间插入或删除元素。但是,在进行大量的随机插入和删除操作时,需要注意维护链表的结构完整性,避免出现指针错误。

   在 Java 的LinkedList中进行频繁的插入和删除操作时,可以通过以下方法避免性能下降: 如果要在链表中间插入或删除元素,可以先使用迭代器找到目标位置,然后使用迭代器的add和remove方法进行操作。这样可以避免在遍历过程中频繁地调用get方法,提高性能。

LinkedList<String> list = new LinkedList<>();
list.add("apple");
list.add("banana");
list.add("cherry");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String element = iterator.next();if (element.equals("banana")) {iterator.remove(); // 删除元素}
}
iterator = list.iterator();
while (iterator.hasNext()) {String element = iterator.next();if (element.equals("apple")) {iterator.add("orange"); // 在元素后插入}
}

   5.2 遍历方式选择

  • 可以使用迭代器、增强型 for 循环和普通 for 循环进行遍历。如果只需要顺序遍历链表,迭代器和增强型 for 循环是比较好的选择,简洁且高效。如果需要在遍历过程中同时进行插入或删除操作,迭代器是更安全的方式,因为它可以正确地处理链表结构的变化。

  5.3 LinkedList插入和删除元素的平均时间复杂度为 O(1),但在某些特殊情况下可能接近 O(n)。

  插入操作:

  在链表头部插入元素:只需要更新一个指针,将新节点的next指向原来的头节点,然后更新头节点为新节点。时间复杂度为 O(1)。

public void addFirst(E e) {linkFirst(e);
}private void linkFirst(E e) {final Node<E> f = first;final Node<E> newNode = new Node<>(null, e, f);first = newNode;if (f == null)last = newNode;elsef.prev = newNode;size++;modCount++;
}

  在链表尾部插入元素:同样只需要更新一个指针,将新节点的prev指向原来的尾节点,然后更新尾节点为新节点。时间复杂度为 O(1)。

public void addLast(E e) {linkLast(e);
}void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++;
}

   在链表中间插入元素:需要先找到插入位置,然后调整前后节点的指针。如果已知插入位置的前驱节点,那么插入操作的时间复杂度为 O(1);如果需要从头开始遍历找到插入位置,那么时间复杂度接近 O(n),其中 n 是链表的长度。

   删除链表中间元素:需要先找到要删除的节点,然后调整前后节点的指针。如果已知要删除节点的前驱节点,那么删除操作的时间复杂度为 O(1);如果需要从头开始遍历找到要删除的节点,那么时间复杂度接近 O(n),其中 n 是链表的长度。

  5.4 类型安全问题

  在使用LinkedList时,需要注意类型安全问题。如果存储不同类型的元素,可能会引发ClassCastException异常。可以使用泛型来确保链表中存储的元素类型一致。 

​
LinkedList list = new LinkedList();
list.add(10);
list.add("hello");
int number = (int) list.get(1); // 这里会抛出 ClassCastException​

  5.5集合类之间的转换

  可以将LinkedList转换为其他集合类,例如使用toArray()方法将其转换为数组,或者使用ArrayList的构造函数将其转换为ArrayList。但在进行转换时,需要注意数据类型的兼容性和性能开销。

  5.6 并发修改异常

  • 在使用迭代器遍历LinkedList的同时进行修改操作(如添加或删除元素),可能会导致ConcurrentModificationException异常。因为迭代器在遍历过程中会维护一个修改计数器,当检测到集合被外部修改时,就会抛出异常。为了避免这种情况,可以使用迭代器的remove()方法在遍历过程中进行安全的删除操作,或者在修改后重新获取迭代器。

LinkedList<String> list = new LinkedList<>();
list.add("apple");
list.add("banana");
list.add("cherry");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String element = iterator.next();if (element.equals("banana")) {list.remove(element); // 这里会抛出 ConcurrentModificationException}
}

1. 如果在多线程环境下使用LinkedList,可以考虑使用并发安全的集合类,

如:ConcurrentLinkedQueue。这些集合类在设计时考虑了多线程并发访问的情况,提供了更高的性能和线程安全性。

2. 如果必须使用LinkedList,可以使用同步机制来保护对链表的访问。例如,可以使用synchronized关键字或者ReentrantLock来确保在多线程环境下对链表的操作是线程安全的。但需要注意同步带来的性能开销。

  5.7 空指针处理

  • 当从LinkedList中获取元素时,需要注意处理可能返回的null值,以避免空指针异常。特别是在使用迭代器遍历链表时,要确保对每个元素进行适当的空指针检查。

  5.8 内存管理问题

  1. 内存泄漏:如果在使用LinkedList的过程中,没有正确地管理对链表中元素的引用,可能会导致内存泄漏。例如,如果一个元素被插入到链表中,但在后续的操作中不再被需要,却仍然被链表中的节点引用着,那么这个元素所占用的内存就无法被垃圾回收器回收。方案:及时清理无用的引用:如果一个元素从链表中被删除,确保其引用被及时设置为null,以便垃圾回收器可以回收其占用的内存。

  2. 内存浪费:由于LinkedList的每个节点都需要额外的内存来存储前后节点的引用,对于存储大量小元素的情况,可能会导致相对较高的内存开销。相比之下,数组或其他更紧凑的数据结构可能会更节省内存。(方案:选择合适的数据结构)

  5.9特殊用途

  1. 双向链表的优势:LinkedList是双向链表,这意味着可以从链表的头部和尾部两个方向进行快速的插入和删除操作。例如,可以使用addFirst和removeFirst方法在链表头部进行高效的操作,这在一些特定的算法和数据结构中可能非常有用,如实现栈或队列的数据结构。

  2. 作为队列或栈的实现:虽然 Java 中有专门的Queue和Stack接口以及相应的实现类,但LinkedList可以很容易地用作队列或栈。例如,通过只使用addLast和removeFirst方法,可以将LinkedList用作队列;通过只使用addFirst和removeFirst方法,可以将其用作栈。

  3. 与其他数据结构的转换:LinkedList可以与其他数据结构进行转换,这在一些特定的场景下可能很有用。例如,可以将LinkedList转换为数组,或者将其转换为另一种集合类型。但在进行转换时,需要注意性能和类型安全问题。

  5.10 内存布局细节

  1. 节点结构:LinkedList的节点不仅包含数据元素,还包含前后节点的引用。这使得每个节点占用的内存相对较大,尤其是在存储小数据量时,与其他数据结构相比可能存在一定的内存浪费。例如,存储大量小整数时,ArrayList可能在内存使用上更加紧凑,因为它是基于数组实现的,而LinkedList的每个节点都需要额外的空间来存储指针。

  2. 内存碎片化:由于LinkedList的节点在内存中是分散存储的,频繁的插入和删除操作可能导致内存碎片化。虽然 Java 的垃圾回收机制会处理不再使用的节点,但在某些情况下,内存碎片化可能会影响程序的性能,尤其是在长时间运行的程序中。

  5.11 性能特性的微妙之处

  1. 遍历性能:虽然在插入和删除操作上表现出色,但LinkedList的遍历性能相对较差。这是因为在遍历过程中,需要逐个节点地通过指针进行访问,而不能像ArrayList那样通过索引快速定位元素。例如,在一个大型的LinkedList中进行顺序遍历可能比在同等大小的ArrayList中遍历要慢得多。

  2. 大尺寸链表的性能下降:当LinkedList变得非常大时,一些操作的性能可能会急剧下降。例如,在一个包含数十万甚至更多节点的链表中进行插入或删除操作,可能会因为需要遍历较长的距离来找到插入或删除位置而变得非常耗时。



 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/419690.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

免费的月考成绩发布小程序

月考成绩出炉&#xff0c;老师们便开始了一项既繁琐又耗时的工作&#xff1a;将成绩单私信给每位学生家长。需要老师们在繁忙的教学工作中抽出自己额外休息的时间&#xff0c;还要确保每位家长都能及时准确的收到自己孩子的成绩单。然而&#xff0c;随着科技的发展&#xff0c;…

Delphi5数据控制组件——查询

文章目录 效果图参考查询Free方法Close方法总结通俗理解 完整代码 效果图 参考 本文是在上一篇的基础上&#xff0c;将查询页面重新写一次。 查询 {点击查询} procedure TForm2.Button1Click(Sender: TObject); vartj,tj1,tj2,tj3,tj4,tj5,tj6,tj7:string; begin//按照工号查…

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建 首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件…

[ios]准备好app后使用xcode发布ios操作

在app代码完成后&#xff0c;点击xcode进行发布

船舶机械设备5G智能工厂物联数字孪生平台,推进制造业数字化转型

船舶机械设备5G智能工厂物联数字孪生平台&#xff0c;推进制造业数字化转型。在当今数字化浪潮推动下&#xff0c;船舶制造业正经历着前所未有的变革。为了应对市场的快速变化&#xff0c;提升生产效率&#xff0c;降低成本&#xff0c;并增强国际竞争力&#xff0c;船舶机械设…

【无人机设计与控制】旋转无人机摆锤的SDRE仿真

摘要 旋转无人机摆锤&#xff08;Double Rotor Pendulum, DRP&#xff09;系统的稳定性控制是现代飞行控制领域的一个挑战性课题。本文采用了状态依赖黎卡提方程&#xff08;SDRE&#xff09;方法对该系统进行建模和仿真&#xff0c;以实现摆锤的稳定控制。通过SDRE方法&#…

内卷时代无人机培训机构如何做大做强

在当今社会&#xff0c;随着科技的飞速发展&#xff0c;“内卷”一词频繁被提及&#xff0c;反映了各行业竞争日益激烈的现象。对于无人机培训行业而言&#xff0c;如何在这样的时代背景下脱颖而出&#xff0c;实现做大做强的目标&#xff0c;成为每个培训机构必须深思的问题。…

ComfyUI+Krea免费利用AI制作网站萌宠IP,五步搞定制作AI萌宠

大家好&#xff0c;这是我们网站的萌宠——Meo喵&#xff0c;是一只猫咪AI工具专家&#x1f43e;&#xff0c;嘻嘻&#x1f389;&#x1f431;。是AIGC年轻的艺术家星之&#xff0c;利用AI产品ComfyUI、Krea&#xff0c;搭配PS制作而成&#xff0c;下面先介绍一下它的形象&…

COD论文笔记 Adaptive Guidance Learning for Camouflaged Object Detection

论文的主要动机、现有方法的不足、拟解决的问题、主要贡献和创新点如下&#xff1a; 动机&#xff1a; 论文的核心动机是解决伪装目标检测&#xff08;COD&#xff09;中的挑战性任务。伪装目标检测旨在识别和分割那些在视觉上与周围环境高度相似的目标&#xff0c;这对于计算…

Bev pool 加速(2):自定义c++扩展

文章目录 1. c++扩展2. 案例2.1 案例12. 1.1 代码实现(1) c++ 文件(2) setup.py编写(3) python 代码编写2.1 案例1在bevfusion论文中,将bev_pooling定义为view transform中的效率瓶颈,bevfusion 主要就是对bev_pooling进行了加速,使得视图转换的速度提高了40倍,延迟从500ms…

假期学习-- iOS 通知详解

iOS 通知详解 数据结构 从我们之前使用通知的流程和代码来看&#xff0c;通知其实就是一个单例&#xff0c;方便随时访问。 NSNotificationCenter&#xff1a;消息中心 这个单例类中主要定义了两个表&#xff0c;一个存储所有注册通知信息的表的结构体&#xff0c;一个保存…

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础&#xff1a;WAV专题&#xff08;6&#xff09;——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道&#xff0c;通过FFprobe命令可以打印WAV音频文件每个packet&#xff08;也称为数据包或多媒体包&#xff09;的信息&#xff0…

程序员要失业了,一行代码没写,就完成了一个个人简历网页模版的创建

今天发现了一个好用的工——Cursor, 真的一行代码都没有写&#xff0c;完成了一个个人简历网页的创建&#xff0c;快来体验一下吧&#xff01; 官网: https://www.cursor.com/ 价格&#xff08;近乎免费&#xff09; 先来看一下价格&#xff0c;cursor 非免费&#xff0c;但是…

[数据集][目标检测]肺炎检测数据集VOC+YOLO格式4983张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4983 标注数量(xml文件个数)&#xff1a;4983 标注数量(txt文件个数)&#xff1a;4983 标注…

springboot个性化大学生线上聊天交友系统

基于springbootvue实现的个性化大学生线上聊天交友系统 &#xff08;源码L文ppt&#xff09;4-017 4系统设计 4.1 软件功能模块设计 个性化大学生线上聊天交友分为两个模块&#xff0c;分别是管理员功能模块和用户功能模块。主要功能模块包括&#xff…

如何实现输入手机号查询座位号或桌号?

如何通过关键词查询信息&#xff1f; 一、简介 在大型活动中&#xff0c;如公司年会&#xff0c;快速定位座位或桌号对于参与者来说非常重要。本文将指导您如何使用云分组小程序&#xff0c;通过输入手机号来查询座位号或桌号&#xff0c;确保每位参与者都能轻松找到自己的座位…

uniapp交互反馈

页面交互反馈可以通过:uni.showToast(object)实现,常用属性有 ioc值说明 值说明success显示成功图标&#xff0c;此时 title 文本在小程序平台最多显示 7 个汉字长度&#xff0c;App仅支持单行显示。error显示错误图标&#xff0c;此时 title 文本在小程序平台最多显示 7 个汉字…

51单片机个人学习笔记11(AT24C02-I2C总线)

前言 本篇文章属于STC89C52单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 [1-1] 课程简介_哔哩…

【Qt| 入门知识】怎样创建一个最简单 Qt 界面程序

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-09-09 …

开启计算机的ssh 22端口

当我们使用一台服务器的时候&#xff0c;经常需要开启ssh 服务&#xff0c;有些系统没有默认开启服务&#xff0c;需要需要我们做一些配置&#xff0c;以下是完整配置过程和错误解决方法&#xff1a; 以下过程适合于当我们购买一台云主机时候配置远程登录 开启本地计算机的22…