首页 文章 精选 留言 我的

精选列表

搜索[计算机组成原理],共10000篇文章
优秀的个人博客,低调大师

[转载] Spark Streaming 设计原理

本文转自:https://zhuanlan.zhihu.com/p/47838090. 本站转载已经过作者授权。如需转载,请和原作者联系。 最近两年流式计算又开始逐渐火了起来,说到流式计算主要分两种:continuous-based 和 micro-batch。最近在使用基于 micro-batch 模式的 Spark Streaming,正好结合论文介绍一下。这里说的论文是 2013 年发布的 《Discretized Streams: Fault-Tolerant Streaming Computation at Scale》,虽然是 2013 年发表的论文,但是系统的核心逻辑基本没怎么变化,对于理解 Spark Streaming 的系统设计、工作方式还是很有帮助的。注:Spark 在 2016 年推出了 Structur

优秀的个人博客,低调大师

SpringBoot 原理之 yaml 解析

导入 SpringBoot 的 snakeyaml 解析包 编写 yaml 文件 编写 yaml 文件对应的 class 编写 main 进行获取 导入 SpringBoot 的 snakeyaml 解析包 <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.23</version> </dependency> 编写 yaml 文件 id: 110 name: 'stuName' gender: '男' clas: id: 110 name: 'classesName' describe: 'describe' 编写 yaml 文件对应的 class public class Student { private Integer id; private String name; private String gender; private Classes clas; // getter(), setter(), toString(); } class Classes { private Integer id; private String name; private String describe; // getter(), setter(), toString(); } 编写 main 进行获取 public static void main(String[] args) { Yaml yaml = new Yaml(); Student result = yaml.loadAs(thisClass.class.getClassLoader() .getResourceAsStream("springboot.yaml"), Student.class); System.out.println(result); }

优秀的个人博客,低调大师

Kubernetes API server工作原理

作为Kubernetes的使用者,每天用得最多的命令就是kubectl XXX了。 kubectl其实就是一个控制台,主要提供的功能: 1. 提供Kubernetes集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更; 2. 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd) 也就是说,我们在终端里输入的每个kubectl命令,实际上都是一个发往Kubernetes API server的Restful API调用。 我们可以做个实验: kubectl get secret -v=9, 通过-v=9设置最高级别的trace: 从输出观察到为了取回所有的secret而进行的API server的调用url:https://xxxx/api/v1/

优秀的个人博客,低调大师

java NIO 运行原理介绍

开篇 回想研究生期间在H3C做项目的时候第一次接触epoll的异步事件,心血来潮看了下java的NIO的实现,希望同样感兴趣的人一起看看。Netty是java NIO的集大成者,一定要看看。 java NIO server demo socket server端工作标准流程 创建socket: 创建ServerSocketChannel,通过ServerSocketChannel.open()方法。 绑定socket:ServerSocketChannel绑定端口,通过serverSocketChannel.bind()方法。 前置准备: 创建selector对象,通过Selector.open()方法。 前置准备: 注册Channel到selector并绑定事件,通过serverSocketChannel.register()。 监听端口号: 通过listen()方法开始进入监听。 处理事件: while循环中等待select操作返回区分连接还是数据进行不同处理。 public class NIOServer { private Selector selector; public void initServer(int port) throws IOException { // 获得一个ServerSocketChannel通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 设置通道为非阻塞 serverSocketChannel.configureBlocking(false); // 将该通道对应的ServerSocket绑定到port端口 serverSocketChannel.bind(new InetSocketAddress(port)); // 获得一个通道管理器 this.selector = Selector.open(); // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后, // 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } public void listen() throws IOException { System.out.println("服务端启动成功!"); // 轮询访问selector while (true) { // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞 selector.select(); // 获得selector中选中的项的迭代器,选中的项为注册的事件 Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator(); while (ite.hasNext()) { SelectionKey key = (SelectionKey) ite.next(); // 删除已选的key,以防重复处理 ite.remove(); if (key.isAcceptable()) {// 客户端请求连接事件 ServerSocketChannel server = (ServerSocketChannel) key.channel(); // 获得和客户端连接的通道 SocketChannel channel = server.accept(); // 设置成非阻塞 channel.configureBlocking(false); // 在这里可以给客户端发送信息哦 channel.write(ByteBuffer.wrap(new String("向客户端发送了一条信息") .getBytes("utf-8"))); // 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。 channel.register(this.selector, SelectionKey.OP_READ); } else if (key.isReadable()) {// 获得了可读的事件 read(key); } } } } public void read(SelectionKey key) throws IOException { // 服务器可读取消息:得到事件发生的Socket通道 SocketChannel channel = (SocketChannel) key.channel(); // 创建读取的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(512); channel.read(buffer); byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("服务端收到信息:" + msg); ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes("utf-8")); channel.write(outBuffer);// 将消息回送给客户端 } public static void main(String[] args) throws IOException { NIOServer server = new NIOServer(); server.initServer(8000); server.listen(); } } ServerSocketChannel和Selector初始化过程 在java NIO Server的标准过程中,有两个核心的操作需要深入分析一下,分别是ServerSocketChannel.open() 和 Selector.open()两个过程,这里针对这两个对象的初始化流程进行下细致的分解。 // ServerSocketChannel的初始化过程 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // Selector的初始化过程 selector = Selector.open(); 通用逻辑抽取 ServerSocketChannel.open()=SelectorProvider.provider().openServerSocketChannel() Selector.open()=SelectorProvider.provider().openSelector() 两者有共同点在于都调用了SelectorProvider.provider()方法,所以先把相同部分进行分析。 public abstract class ServerSocketChannel extends AbstractSelectableChannel implements NetworkChannel { protected ServerSocketChannel(SelectorProvider provider) { super(provider); } public static ServerSocketChannel open() throws IOException { return SelectorProvider.provider().openServerSocketChannel(); } } public abstract class Selector implements Closeable { protected Selector() { } public static Selector open() throws IOException { return SelectorProvider.provider().openSelector(); } } SelectorProvider对象创建 SelectorProvider.provider()方法会在内部创建唯一的SelectorProvider对象,通过锁来保证创建唯一对象。 SelectorProvider对象通过DefaultSelectorProvider.create()方法进行创建。 DefaultSelectorProvider.create()方法内部根据实际系统创建不同的对象,以linux环境中EPollSelectorProvider对象为例继续分析。 public abstract class SelectorProvider { private static final Object lock = new Object(); private static SelectorProvider provider = null; public static SelectorProvider provider() { synchronized (lock) { if (provider != null) return provider; return AccessController.doPrivileged( new PrivilegedAction<SelectorProvider>() { public SelectorProvider run() { if (loadProviderFromProperty()) return provider; if (loadProviderAsService()) return provider; provider = sun.nio.ch.DefaultSelectorProvider.create(); return provider; } }); } } } public class DefaultSelectorProvider { public static SelectorProvider create() { String osname = AccessController.doPrivileged( new GetPropertyAction("os.name")); if ("SunOS".equals(osname)) { return new sun.nio.ch.DevPollSelectorProvider(); } // use EPollSelectorProvider for Linux kernels >= 2.6 if ("Linux".equals(osname)) { String osversion = AccessController.doPrivileged( new GetPropertyAction("os.version")); String[] vers = osversion.split("\\.", 0); if (vers.length >= 2) { try { int major = Integer.parseInt(vers[0]); int minor = Integer.parseInt(vers[1]); if (major > 2 || (major == 2 && minor >= 6)) { return new sun.nio.ch.EPollSelectorProvider(); } } catch (NumberFormatException x) { // format not recognized } } } return new sun.nio.ch.PollSelectorProvider(); } } EPollSelectorProvider的操作过程 SelectorProvider.provider().openServerSocketChannel()调用EPollSelectorProvider的openServerSocketChannel()方法返回EPollSelectorImpl对象。 SelectorProvider.provider().openSelector()调用EPollSelectorProvider的openSelector()方法返回ServerSocketChannelImpl对象。 继续分析ServerSocketChannelImpl对象和EPollSelectorImpl对象。 public class EPollSelectorProvider extends SelectorProviderImpl { public AbstractSelector openSelector() throws IOException { return new EPollSelectorImpl(this); } public Channel inheritedChannel() throws IOException { return InheritedChannel.getChannel(); } } public abstract class SelectorProviderImpl extends SelectorProvider { public DatagramChannel openDatagramChannel() throws IOException { return new DatagramChannelImpl(this); } public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException { return new DatagramChannelImpl(this, family); } public Pipe openPipe() throws IOException { return new PipeImpl(this); } public abstract AbstractSelector openSelector() throws IOException; public ServerSocketChannel openServerSocketChannel() throws IOException { return new ServerSocketChannelImpl(this); } public SocketChannel openSocketChannel() throws IOException { return new SocketChannelImpl(this); } } EPollSelectorImpl对象 EPollSelectorImpl构造函数创建内部通信的socket对IOUtil.makePipe(false)。 EPollSelectorImpl的doSelect方法负责返回事件到来的fds。 EPollSelectorImpl的fdToKey的map保存fd和SelectionKey的映射。 class EPollSelectorImpl extends SelectorImpl { // File descriptors used for interrupt protected int fd0; protected int fd1; // The poll object EPollArrayWrapper pollWrapper; // Maps from file descriptors to keys private Map<Integer,SelectionKeyImpl> fdToKey; // True if this Selector has been closed private volatile boolean closed = false; // Lock for interrupt triggering and clearing private Object interruptLock = new Object(); private boolean interruptTriggered = false; EPollSelectorImpl(SelectorProvider sp) { super(sp); long pipeFds = IOUtil.makePipe(false); fd0 = (int) (pipeFds >>> 32); fd1 = (int) pipeFds; pollWrapper = new EPollArrayWrapper(); pollWrapper.initInterrupt(fd0, fd1); fdToKey = new HashMap<Integer,SelectionKeyImpl>(); } protected int doSelect(long timeout) throws IOException { if (closed) throw new ClosedSelectorException(); processDeregisterQueue(); try { begin(); // 等待事件到来,收集事件到来的socket的fd并用来处理 pollWrapper.poll(timeout); } finally { end(); } processDeregisterQueue(); // 更新需要写入的keys int numKeysUpdated = updateSelectedKeys(); if (pollWrapper.interrupted()) { // Clear the wakeup pipe pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0); synchronized (interruptLock) { pollWrapper.clearInterrupted(); IOUtil.drain(fd0); interruptTriggered = false; } } return numKeysUpdated; } private int updateSelectedKeys() { int entries = pollWrapper.updated; int numKeysUpdated = 0; for (int i=0; i<entries; i++) { int nextFD = pollWrapper.getDescriptor(i); SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD)); // ski is null in the case of an interrupt if (ski != null) { int rOps = pollWrapper.getEventOps(i); if (selectedKeys.contains(ski)) { if (ski.channel.translateAndSetReadyOps(rOps, ski)) { numKeysUpdated++; } } else { ski.channel.translateAndSetReadyOps(rOps, ski); if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) { // selectedKeys保存ski也就是事件到的socket连接 // ski的对象数据结构需要好好研究一下 selectedKeys.add(ski); numKeysUpdated++; } } } } return numKeysUpdated; } } ServerSocketChannelImpl对象 ServerSocketChannelImpl extends ServerSocketChannel ServerSocketChannel extends AbstractSelectableChannel ServerSocketChannelImpl对象提供bind()&accept()方法 ServerSocketChannelImpl的accept方法内部创建新连接的SocketChannelImpl对象返回 class ServerSocketChannelImpl extends ServerSocketChannel implements SelChImpl { private final Object stateLock = new Object(); private SocketAddress localAddress; ServerSocket socket; ServerSocketChannelImpl(SelectorProvider sp) throws IOException { super(sp); this.fd = Net.serverSocket(true); this.fdVal = IOUtil.fdVal(fd); this.state = ST_INUSE; } ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) throws IOException { super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_INUSE; if (bound) localAddress = Net.localAddress(fd); } @Override public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { // 省略相关代码 } public SocketChannel accept() throws IOException { // 省略相关代码 } } public abstract class AbstractSelectableChannel extends SelectableChannel { protected AbstractSelectableChannel(SelectorProvider provider) { this.provider = provider; } public final SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException { synchronized (regLock) { if (!isOpen()) throw new ClosedChannelException(); if ((ops & ~validOps()) != 0) throw new IllegalArgumentException(); if (blocking) throw new IllegalBlockingModeException(); SelectionKey k = findKey(sel); if (k != null) { k.interestOps(ops); k.attach(att); } if (k == null) { // New registration synchronized (keyLock) { if (!isOpen()) throw new ClosedChannelException(); k = ((AbstractSelector)sel).register(this, ops, att); addKey(k); } } return k; } } } select过程 select执行过程 执行selector.select()操作时实际是调用了子类实现的doSelect()方法。 进一步跟进子类的doSelect()方法。 abstract class SelectorImpl extends AbstractSelector { // 保存事件到来的keys protected Set<SelectionKey> selectedKeys; protected HashSet<SelectionKey> keys; private Set<SelectionKey> publicKeys; // Immutable private Set<SelectionKey> publicSelectedKeys; // Removal allowed, but not addition protected abstract int doSelect(long timeout) throws IOException; private int lockAndDoSelect(long timeout) throws IOException { synchronized (this) { if (!isOpen()) throw new ClosedSelectorException(); synchronized (publicKeys) { synchronized (publicSelectedKeys) { return doSelect(timeout); } } } } public int select(long timeout) throws IOException { if (timeout < 0) throw new IllegalArgumentException("Negative timeout"); return lockAndDoSelect((timeout == 0) ? -1 : timeout); } public int select() throws IOException { return select(0); } public Set<SelectionKey> selectedKeys() { if (!isOpen() && !Util.atBugLevel("1.4")) throw new ClosedSelectorException(); return publicSelectedKeys; } } pollWrapper.poll(timeout)以超时等待的形式等待epoll的消息通知。 通过updateSelectedKeys方法收集有事件到达的fds保存到selectedKeys。 class EPollSelectorImpl extends SelectorImpl { protected int doSelect(long timeout) throws IOException { if (closed) throw new ClosedSelectorException(); processDeregisterQueue(); try { begin(); // 等待事件到来,收集事件到来的socket的fd并用来处理 pollWrapper.poll(timeout); } finally { end(); } processDeregisterQueue(); // 更新需要写入的keys int numKeysUpdated = updateSelectedKeys(); if (pollWrapper.interrupted()) { // Clear the wakeup pipe pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0); synchronized (interruptLock) { pollWrapper.clearInterrupted(); IOUtil.drain(fd0); interruptTriggered = false; } } return numKeysUpdated; } private int updateSelectedKeys() { int entries = pollWrapper.updated; int numKeysUpdated = 0; for (int i=0; i<entries; i++) { int nextFD = pollWrapper.getDescriptor(i); SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD)); // ski is null in the case of an interrupt if (ski != null) { int rOps = pollWrapper.getEventOps(i); if (selectedKeys.contains(ski)) { if (ski.channel.translateAndSetReadyOps(rOps, ski)) { numKeysUpdated++; } } else { ski.channel.translateAndSetReadyOps(rOps, ski); if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) { // selectedKeys保存ski也就是事件到的socket连接 // ski的对象数据结构需要好好研究一下 selectedKeys.add(ski); numKeysUpdated++; } } } } return numKeysUpdated; } } accept过程 accept的过程很简单就是accept新socket并创建SocketChannelImpl返回即可。 SocketChannelImpl对象后面需要注册到Selector当中所以需要进一步分析。 public SocketChannel accept() throws IOException { // 省略相关代码 try { // 省略相关代码 // 新accept的socket放在newfd当中 n = accept0(this.fd, newfd, isaa); } } IOUtil.configureBlocking(newfd, true); InetSocketAddress isa = isaa[0]; // 通过SocketChannelImpl包装newfd对象 sc = new SocketChannelImpl(provider(), newfd, isa); // 省略相关代码 return sc; } } SocketChannelImpl对象 SocketChannelImpl可以理解为普通Socket的封装,包括read/write等方法 SocketChannelImpl extends SocketChannel extends AbstractSelectableChannel AbstractSelectableChannel提供register到selector对象的方法 class SocketChannelImpl extends SocketChannel implements SelChImpl { SocketChannelImpl(SelectorProvider sp) throws IOException { super(sp); this.fd = Net.socket(true); this.fdVal = IOUtil.fdVal(fd); this.state = ST_UNCONNECTED; } SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) throws IOException { super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_UNCONNECTED; if (bound) this.localAddress = Net.localAddress(fd); } SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, InetSocketAddress remote) throws IOException { super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_CONNECTED; this.localAddress = Net.localAddress(fd); this.remoteAddress = remote; } public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { // 读数据的逻辑 } public int write(ByteBuffer buf) throws IOException { // 写数据的逻辑 } } register过程 register过程并没有调用epollCtl方法添加fd到selector当中 register过程真正是保存fd到待绑定的列表当中 在SelectorImpl中执行pollWrapper.poll(timeout)方法先把fd列表执行epollCtl添加selector当中,在通过epollWait获取事件到来 public abstract class AbstractSelectableChannel extends SelectableChannel { public final SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException { synchronized (regLock) { if (!isOpen()) throw new ClosedChannelException(); if ((ops & ~validOps()) != 0) throw new IllegalArgumentException(); if (blocking) throw new IllegalBlockingModeException(); SelectionKey k = findKey(sel); if (k != null) { k.interestOps(ops); k.attach(att); } if (k == null) { // New registration synchronized (keyLock) { if (!isOpen()) throw new ClosedChannelException(); k = ((AbstractSelector)sel).register(this, ops, att); addKey(k); } } return k; } } } abstract class SelectorImpl extends AbstractSelector { protected final SelectionKey register(AbstractSelectableChannel ch, int ops, Object attachment) { if (!(ch instanceof SelChImpl)) throw new IllegalSelectorException(); SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this); k.attach(attachment); synchronized (publicKeys) { implRegister(k); } k.interestOps(ops); return k; } } abstract class AbstractPollSelectorImpl extends SelectorImpl { protected void implRegister(SelectionKeyImpl ski) { synchronized (closeLock) { if (closed) throw new ClosedSelectorException(); // Check to see if the array is large enough if (channelArray.length == totalChannels) { // Make a larger array int newSize = pollWrapper.totalChannels * 2; SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize]; // Copy over for (int i=channelOffset; i<totalChannels; i++) temp[i] = channelArray[i]; channelArray = temp; // Grow the NativeObject poll array pollWrapper.grow(newSize); } channelArray[totalChannels] = ski; ski.setIndex(totalChannels); // 核心的将channel添加到pollWrapper当中 pollWrapper.addEntry(ski.channel); totalChannels++; keys.add(ski); } } } class EPollArrayWrapper { int poll(long timeout) throws IOException { updateRegistrations(); updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd); for (int i=0; i<updated; i++) { if (getDescriptor(i) == incomingInterruptFD) { interruptedIndex = i; interrupted = true; break; } } return updated; } void updateRegistrations() { synchronized (updateList) { Updator u = null; while ((u = updateList.poll()) != null) { SelChImpl ch = u.channel; if (!ch.isOpen()) continue; // if the events are 0 then file descriptor is put into "idle // set" to prevent it being polled if (u.events == 0) { boolean added = idleSet.add(u.channel); // if added to idle set then remove from epoll if registered if (added && (u.opcode == EPOLL_CTL_MOD)) epollCtl(epfd, EPOLL_CTL_DEL, ch.getFDVal(), 0); } else { // events are specified. If file descriptor was in idle set // it must be re-registered (by converting opcode to ADD) boolean idle = false; if (!idleSet.isEmpty()) idle = idleSet.remove(u.channel); int opcode = (idle) ? EPOLL_CTL_ADD : u.opcode; epollCtl(epfd, opcode, ch.getFDVal(), u.events); } } } } }

优秀的个人博客,低调大师

Java常用算法原理剖析

用Java实现的所有算法(用于教育) 这些只是为了演示的目的。在Java标准库中有许多不同类型的实现,由于性能原因这些要好得多。 排序算法 气泡 从维基百科气泡排序,叫做下沉排序,是一种简单的排序算法,反复遍历要排序的列表,比较每一对相邻的项目,并在排序错误的情况下交换。遍历列表将被重复,直到不需要交换,这表明列表已被排序。 特性 最差情况下的性能O(n^2) 最佳案例表现O(N) 平均病例性能O(n^2) 查看算法行动 插入 从维基百科插入排序是一种简单的排序算法,每次构建最终排序数组(或列表)。在大型列表中,效率要比更高级的算法(如快速排序、堆排序或合并排序)低得多。 特性 最差情况下的性能O(n^2) 最佳案例表现O(N) 平均病例性能O(n^2) 查看算法行动 合并 合并排序(通常也是拼写合并)是一种高效的、通用的、基于比较排序算法。大多数实现都会产生稳定的排序,实现在排序的输出中保留相同元素的输入顺序。Mergesort是由JohnvonNeumann于1945年发明的分而治之的算法。 特性 最坏的情况性能O(N Log N)(典型) 最佳情况性能O(N Log N) 平均情况性能O(N Log N) 查看算法行动 速战速决 从维基百科快速排序(有时称为分区-交换排序)是一种有效的排序算法,是一种系统的方法,用于排列数组的元素。 特性 最差情况下的性能O(n^2) 最佳情况下O(N Log N)或O(N)具有三向分区 平均病例性能O(n^2) 查看算法行动 选择 将输入列表分为两个部分:已经排序项的子列表(在列表的前面(左)从左到右建立)和占据列表其余部分的待排序项的子列表。最开始排序子列表是空的,未排序子列表是整个输入列表。该算法通过查找未排序子列表中最小的(或最大的,取决于排序顺序)元素,将其与最左边的未排序元素交换(按排序顺序排列),并将子列表边界向右移动。 特性 最差情况下的性能O(n^2) 最佳案例性能O(n^2) 平均病例性能O(n^2) 查看算法行动 壳 ShellSort是插入排序的一种推广,允许交换相距很远的项。思路是安排元素列表,以便从任何地方开始,考虑到每个第n个元素都会给出一个排序列表。这样的列表叫做h排序。等效地,可以被认为是h交错列表,每个元素都是单独排序的。 特性 最坏的性能O(Nlog 2 2n) 最佳情况性能O(N Log N) 平均病例性能取决于间隙序列 查看算法行动 时间紧图 比较排序算法(气泡排序、插入排序、选择排序)的复杂性 复杂性图 搜索算法 线性 线性搜索或顺序搜索是在列表中查找目标值的一种方法。会依次检查列表中的每个元素的目标值,直到找到匹配或搜索所有元素为止。线性搜索在最坏的线性时间运行,最多进行n个比较,其中n是列表的长度。 特性 最坏的性能O(N) 最佳案例表现O(1) 平均个案表现O(N) 最坏情况下空间复杂度O(1)迭代 二进制 此算法也叫半间隔搜索或对数搜索算法,查找目标值在排序数组中的位置。将目标值与数组的中间元素进行比较;如果不相等,则消除目标数组的一半,并在其余的一半上继续搜索,直到成功为止。 特性 最坏的性能O(Log N) 最佳案例表现O(1) 平均案例性能O(Log N) 最坏情况空间复杂度O(1) ShellSort是插入排序的一种推广,允许交换相距很远的项。思路是安排元素列表,便于任何地方开始,考虑到每个第n个元素都会给出一个排序列表。这样的列表叫做h排序。等效地,可以被认为是h交错列表,每个元素都是单独排序的。 特性 最坏的性能O(Nlog 2 2n) 最佳情况性能O(N Log N) 平均病例性能取决于间隙序列 查看算法行动 与其他算法的链接 转换 动态规划 密码 杂类 任何基地到任何基地 硬币兑换 凯撒沙拉 堆排序 任何基到十进制 蛋滴 柱状转位密码 回文素校验器 二进制到十进制 斐波纳契 RSA 很快.。 二进制到十六进制 Kadane算法 更多的很快就会到来.。 二进制到八进制 背包 十进制到任意基 最长公共子序列 十进制到二进制 最长增长子序列 十进制到十六进制 棒材切割 还有更多.。 还有更多.。 数据结构 图 堆 列表 排队 BFS 空堆异常 圆链表 通用数组列表队列 外勤部 堆 双链表 排队 图 堆元素 单链表 Kruskals算法 最大堆 矩阵图 民堆 PrimMST 堆叠 树 节点堆栈 AVL树 链表堆栈 二叉树 堆叠 还有更多.。 袋 缓冲器 HashMap 矩阵

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册