Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Netty | 工作流程 & 核心组件讲解 & 代码案例

Netty | 工作流程 & 核心组件讲解 & 代码案例

作者头像
宁在春
发布于 2022-10-31 07:47:52
发布于 2022-10-31 07:47:52
5.5K00
代码可运行
举报
运行总次数:0
代码可运行

前文:你的第一款Netty应用程序 前一篇文章写了第一款Netty入门的应用程序,本文主要就是从上文的代码结合本文的流程图进一步分析Netty的工作流程和核心组件。 最后再进一步举一个实例来让大家进一步理解。 希望能够让你有所收获!!🚀

一、Netty 工作流程

我们先来看看Netty的工作原理图,简单说一下工作流程,然后通过这张图来一一分析Netty的核心组件。

1.1、Server工作流程图:

1.2、Server工作流程分析:

  1. server端启动时绑定本地某个端口,初始化NioServerSocketChannel.
  2. 将自己NioServerSocketChannel注册到某个BossNioEventLoopGroup的selector上。
    • server端包含1个Boss NioEventLoopGroup和1个Worker NioEventLoopGroup
    • Boss NioEventLoopGroup专门负责接收客户端的连接,Worker NioEventLoopGroup专门负责网络的读写
    • NioEventLoopGroup相当于1个事件循环组,这个组里包含多个事件循环NioEventLoop,每个NioEventLoop包含1个selector和1个事件循环线程。
  3. BossNioEventLoopGroup循环执行的任务: 1、轮询accept事件; 2、处理accept事件,将生成的NioSocketChannel注册到某一个WorkNioEventLoopGroup的Selector上。 3、处理任务队列中的任务,runAllTasks。任务队列中的任务包括用户调用eventloop.execute或schedule执行的任务,或者其它线程提交到该eventloop的任务。
  4. WorkNioEventLoopGroup循环执行的任务:
    • 轮询read和Write事件
    • 处理IO事件,在NioSocketChannel可读、可写事件发生时,回调(触发)ChannelHandler进行处理。
    • 处理任务队列的任务,即 runAllTasks

1.3、Client工作流程图

流程就不重复概述啦😁

二、核心模块组件

Netty的核心组件大致是以下几个:

  1. Channel 接口
  2. EventLoopGroup 接口
  3. ChannelFuture 接口
  4. ChannelHandler 接口
  5. ChannelPipeline 接口
  6. ChannelHandlerContext 接口
  7. SimpleChannelInboundHandler 抽象类
  8. Bootstrap、ServerBootstrap 类
  9. ChannelFuture 接口
  10. ChannelOption 类

2.1、Channel 接口

我们平常用到基本的 I/O 操作(bind()、connect()、read()和 write()),其本质都依赖于底层网络传输所提供的原语,在Java中就是Socket类。

Netty 的 Channel 接 口所提供的 API,大大地降低了直接使用Socket 类的复杂性。另外Channel 提供异步的网络 I/O 操作(如建立连接,读写,绑定端口),异步调用意味着任何 I/O 调用都将立即返回,并且不保证在调用结束时所请求的 I/O 操作已完成。

在调用结束后立即返回一个 ChannelFuture 实例,通过注册监听器到 ChannelFuture 上,支持 在I/O 操作成功、失败或取消时立马回调通知调用方。

此外,Channel 也是拥有许多预定义的、专门化实现的广泛类层次结构的根,比如:

  • LocalServerChannel:用于本地传输的ServerChannel ,允许 VM 通信。
  • EmbeddedChannel:以嵌入式方式使用的 Channel 实现的基类。
  • NioSocketChannel:异步的客户端 TCP 、Socket 连接。
  • NioServerSocketChannel:异步的服务器端 TCP、Socket 连接。
  • NioDatagramChannel: 异步的 UDP 连接。
  • NioSctpChannel:异步的客户端 Sctp 连接,它使用非阻塞模式并允许将SctpMessage读/写到底层SctpChannel。
  • NioSctpServerChannel:异步的 Sctp 服务器端连接,这些通道涵盖了 UDP 和 TCP 网络 IO 以及文件 IO。

2.2、EventLoopGroup接口

EventLoop 定义了Netty的核心抽象,用于处理连接的生命周期中所发生的事件。

Netty 通过触发事件将 Selector 从应用程序中抽象出来,消除了所有本来将需要手动编写 的派发代码。在内部,将会为每个 Channel 分配一个 EventLoop,用以处理所有事件,包括:

  • 注册事件;
  • 将事件派发给 ChannelHandler;
  • 安排进一步的动作。

不过在这里我们不深究它,针对 Channel、EventLoop、Thread 以及 EventLoopGroup 之间的关系做一个简单说明。

  • 一个EventLoopGroup 包含一个或者多个 EventLoop
  • 每个 EventLoop 维护着一个 Selector 实例,所以一个 EventLoop在它的生命周期内只和一个 Thread 绑定;
  • 因此所有由 EventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理,实际上消除了对于同步的需要;
  • 一个 Channel 在它的生命周期内只注册于一个 EventLoop
  • 一个 EventLoop 可能会被分配给一个或多个Channel
  • 通常一个服务端口即一个 ServerSocketChannel 对应一个 Selector 和一个 EventLoop 线程。BossEventLoop 负责接收客户端的连接并将 SocketChannel 交给 WorkerEventLoopGroup 来进行 IO 处理,就如上文中的流程图一样。

2.3、ChannelFuture 接口

Netty 中所有的 I/O 操作都是异步的。因为一个操作可能不会 立即返回,所以我们需要一种用于在之后的某个时间点确定其结果的方法。具体的实现就是通过 FutureChannelFutures,其 addListener()方法注册了一个 ChannelFutureListener,以便在某个操作完成时(无论是否成功)自动触发注册的监听事件。

常见的方法有

  • Channel channel(),返回当前正在进行 IO 操作的通道
  • ChannelFuture sync(),等待异步操作执行完毕

2.4、ChannelHandler 接口

从之前的入门程序中,我们可以看到ChannelHandler在Netty中的重要性,它充当了所有处理入站和出站数据的应用程序逻辑的容器。 我们的业务逻辑也大都写在实现的字类中,另外ChannelHandler 的方法是由事件自动触发的,并不需要我们自己派发。

ChannelHandler的实现类或者实现子接口有很多。平时我们就是去继承或子接口,然后重写里面的方法。

最常见的几种Handler:

  • ChannelInboundHandler :接收入站事件和数据
  • ChannelOutboundHandler:用于处理出站事件和数据。

常见的适配器:

  • ChannelInboundHandlerAdapter:用于处理入站IO事件 ChannelInboundHandler实现的抽象基类,它提供了所有方法的实现。 这个实现只是将操作转发到ChannelPipeline的下一个ChannelHandler 。 子类可以覆盖方法实现来改变这一
  • ChannelOutboundHandlerAdapter: 用于处理出站IO事件

我们经常需要自定义一个 Handler 类去继承 ChannelInboundHandlerAdapter,然后通过重写相应方法实现业务逻辑,我们来看看有哪些方法可以重写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
	//注册事件
    public void channelRegistered(ChannelHandlerContext ctx) ;
	// 
    public void channelUnregistered(ChannelHandlerContext ctx);
	//通道已经就绪
    public void channelActive(ChannelHandlerContext ctx);
	
    public void channelInactive(ChannelHandlerContext ctx) ;
    //通道读取数据事件
    public void channelRead(ChannelHandlerContext ctx, Object msg) ;
	//通道读取数据事件完毕
    public void channelReadComplete(ChannelHandlerContext ctx) ;

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt);
	//通道可写性已更改
    public void channelWritabilityChanged(ChannelHandlerContext ctx);
	//异常处理
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
}

2.5、ChannelPipeline 接口

ChannelPipeline 提供了 ChannelHandler 链的容器,并定义了用于在该链上传播入站和出站事件流的 API。当 Channel 被创建时,它会被自动地分配到它专属的 ChannelPipeline。他们的组成关系如下:

一个 Channel包含了一个 ChannelPipeline,而 ChannelPipeline 中又维护了一个由ChannelHandlerContext 组成的双向链表,并且每个ChanneHandlerContext中又关联着一个ChannelHandler

ChannelHandler 安装到 ChannelPipeline 中的过程:

  1. 一个ChannelInitializer的实现被注册到了ServerBootstrap中 ;
  2. ChannelInitializer.initChannel()方法被调用时,ChannelInitializer将在 ChannelPipeline 中安装一组自定义的 ChannelHandler
  3. ChannelInitializer 将它自己从 ChannelPipeline 中移除。

从一个客户端应用程序 的角度来看,如果事件的运动方向是从客户端到服务器端,那么我们称这些事件为出站的,反之 则称为入站的。服务端反之。

如果一个消息或者任何其他的入站事件被读取,那么它会从 ChannelPipeline 的头部 开始流动,并被传递给第一个 ChannelInboundHandler。次此handler处理完后,数据将会被传递给链中的下一个 ChannelInboundHandler。最终,数据将会到达 ChannelPipeline 的尾端,至此,所有处理就结束了。

出站事件会从尾端往前传递到最前一个出站的 handler。出站和入站两种类型的 handler互不干扰。

2.6、ChannelHandlerContext 接口

作用就是使ChannelHandler能够与其ChannelPipeline和其他处理程序交互。因为 ChannelHandlerContext保存channel相关的所有上下文信息,同时关联一个 ChannelHandler 对象, 另外,ChannelHandlerContext 可以通知ChannelPipeline的下一个ChannelHandler以及动态修改它所属的ChannelPipeline

2.7、SimpleChannelInboundHandler 抽象类

我们常常能够遇到应用程序会利用一个 ChannelHandler 来接收解码消息,并在这个Handler中实现业务逻辑,要写一个这样的 ChannelHandler ,我们只需要扩展抽象类 SimpleChannelInboundHandler< T > 即可, 其中T类型是我们要处理的消息的Java类型。

SimpleChannelInboundHandler 中最重要的方法就是void channelRead0(ChannelHandlerContext ctx, T msg)

我们自己实现了这个方法之后,接收到的消息就已经被解码完的消息啦。

举个例子:

2.8、Bootstrap、ServerBootstrap 类

Bootstrap 意思是引导,一个 Netty 应用通常由一个 Bootstrap 开始,主要作用是配置整个 Netty 程序,串联各个组件。

类别

Bootstrap

ServerBootstrap

引导

用于引导客户端

用于引导服务端

在网络编程中作用

用于连接到远程主机和端口

用于绑定到一个本地端口

EventLoopGroup 的数目

1

2

我想大家对于最后一点可能会存有疑惑,为什么一个是1一个是2呢?

因为服务器需要两组不同的 Channel

第一组将只包含一个 ServerChannel,代表服务 器自身的已绑定到某个本地端口的正在监听的套接字。

而第二组将包含所有已创建的用来处理传入客户端连接(对于每个服务器已经接受的连接都有一个)的 Channel

这一点可以上文中的流程图。

2.9、ChannelFuture 接口

异步 Channel I/O 操作的结果。 Netty 中的所有 I/O 操作都是异步的。 这意味着任何 I/O 调用将立即返回,但不保证在调用结束时请求的 I/O 操作已完成。 相反,您将返回一个 ChannelFuture 实例,该实例为您提供有关 I/O 操作的结果或状态的信息。 ChannelFuture 要么未完成,要么已完成。 当 I/O 操作开始时,会创建一个新的未来对象。 新的未来最初是未完成的——它既没有成功,也没有失败,也没有取消,因为 I/O 操作还没有完成。 如果 I/O 操作成功完成、失败或取消,则使用更具体的信息(例如失败原因)将未来标记为已完成。 请注意,即使失败和取消也属于完成状态。

Netty 中所有的 IO 操作都是异步的,不能立刻得知消息是否被正确处理。但是可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过 FutureChannelFutures,他们可以注册一个监听,当操作执行成功或失败时监听会自动触发注册的监听事件

常见的方法有

  • Channel channel(),返回当前正在进行 IO 操作的通道
  • ChannelFuture sync(),等待异步操作执行完毕

2.10、ChannelOption 类

  1. Netty 在创建 Channel 实例后,一般都需要设置 ChannelOption 参数。
  2. ChannelOption 参数如下:
    • ChannelOption.SO_KEEPALIVE :一直保持连接状态
    • ChannelOption.SO_BACKLOG:对应TCP/IP协议listen 函数中的backlog参数,用来初始化服务器可连接队列大小。服务端处理客户端连接请求是顺序处理内,所N博求放在队刚中等待处理,backilog参数指定端来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理, backlog参数指定了队列的大小。

三、应用实例

【案例】:

写一个服务端,两个或多个客户端,客户端可以相互通信。

3.1、服务端 Handler

ChannelHandler的实现类或者实现子接口有很多。平时我们就是去继承或子接口,然后重写里面的方法。

在这里我们就是继承了 SimpleChannelInboundHandler< T > ,这里面许多方法都是大都只要我们重写一下业务逻辑,触发大都是在事件发生时自动调用的,无需我们手动调用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.crush.atguigu.group_chat;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author crush
 */
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {

    /**
     * 定义一个channle 组,管理所有的channel
     * GlobalEventExecutor.INSTANCE) 是全局的事件执行器,是一个单例
     */
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    /**
     * handlerAdded 表示连接建立,一旦连接,第一个被执行
     *              将当前channel 加入到  channelGroup
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        //将该客户加入聊天的信息推送给其它在线的客户端
        /*
        该方法会将 channelGroup 中所有的channel 遍历,并发送 消息,
        我们不需要自己遍历
         */
        channelGroup.writeAndFlush("[客户端]" + channel.remoteAddress() + " 加入聊天" + sdf.format(new java.util.Date()) + " \n");
        channelGroup.add(channel);

    }

    /**
     * 断开连接, 将xx客户离开信息推送给当前在线的客户
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

        Channel channel = ctx.channel();
        channelGroup.writeAndFlush("[客户端]" + channel.remoteAddress() + " 离开了\n");
        System.out.println("channelGroup size" + channelGroup.size());

    }

    /**
     * 表示channel 处于活动状态, 既刚出生 提示 xx上线
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        System.out.println(ctx.channel().remoteAddress() + " 上线了~");
    }

    /**
     * 表示channel 处于不活动状态, 既死亡状态 提示 xx离线了
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        System.out.println(ctx.channel().remoteAddress() + " 离线了~");
    }

    //读取数据
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {

        //获取到当前channel
        Channel channel = ctx.channel();
        //这时我们遍历channelGroup, 根据不同的情况,回送不同的消息

        channelGroup.forEach(ch -> {
            if (channel != ch) { //不是当前的channel,转发消息
                ch.writeAndFlush("[客户]" + channel.remoteAddress() + " 发送了消息" + msg + "\n");
            } else {//回显自己发送的消息给自己
                ch.writeAndFlush("[自己]发送了消息" + msg + "\n");
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //关闭通道
        ctx.close();
    }
}

3.2、服务端 Server 启动

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.crush.atguigu.group_chat;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * @author crush
 */
public class GroupChatServer {

    /**
     * //监听端口
     */
    private int port;

    public GroupChatServer(int port) {
        this.port = port;
    }

    /**
     * 编写run方法 处理请求
     * @throws Exception
     */
    public void run() throws Exception {

        //创建两个线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //8个NioEventLoop
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();

            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //获取到pipeline
                            ChannelPipeline pipeline = ch.pipeline();
                            //向pipeline加入解码器
                            pipeline.addLast("decoder", new StringDecoder());
                            //向pipeline加入编码器
                            pipeline.addLast("encoder", new StringEncoder());
                            //加入自己的业务处理handler
                            pipeline.addLast(new GroupChatServerHandler());
                        }
                    });

            System.out.println("netty 服务器启动");

            ChannelFuture channelFuture = b.bind(port).sync();

            //监听关闭
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new GroupChatServer(7000).run();
    }
}

3.3、客户端 Handler

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.crush.atguigu.group_chat;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
 * @author crush
 */
public class GroupChatClientHandler extends SimpleChannelInboundHandler<String> {
    
    //当前Channel 已从对方读取消息时调用。
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(msg.trim());
    }
}

3.4、客户端 Server

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.crush.atguigu.group_chat;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.util.Scanner;


/**
 * @author crush
 */
public class GroupChatClient {
    
    private final String host;
    private final int port;

    public GroupChatClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void run() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {

                            //得到pipeline
                            ChannelPipeline pipeline = ch.pipeline();
                            //加入相关handler
                            pipeline.addLast("decoder", new StringDecoder());
                            pipeline.addLast("encoder", new StringEncoder());
                            //加入自定义的handler
                            pipeline.addLast(new GroupChatClientHandler());
                        }
                    });

            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            //得到channel
            Channel channel = channelFuture.channel();
            System.out.println("-------" + channel.localAddress() + "--------");
            //客户端需要输入信息
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNextLine()) {
                String msg = scanner.nextLine();
                //通过channel 发送到服务器端
                channel.writeAndFlush(msg + "\r\n");
            }
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new GroupChatClient("127.0.0.1", 7000).run();
    }
}

多个客户端,cv一下即可。

3.5、测试:

测试流程是先启动 服务端 Server,再启动客户端 。

四、自言自语

这篇文章应该算是个存稿了,之前忙其他事情去了😂。

今天的文章就到这里了。 你好,我是博主宁在春主页 如若在文章中遇到疑惑,请留言或私信,或者加主页联系方式,都会尽快回复。 如若发现文章中存在问题,望你能够指正,不胜感谢。 如果觉得对你有所帮助的话,请点个赞再走吧!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
java详细学习路线及路线图
为了便于描述,文中涉及到的代码部分都是用Java语言编写的,其实Java本身对常见的几种数据结构,线性表、栈、队列等都提供了较好的实现,就是我们经常用到的Java集合框架,有需要的可以阅读这篇文章。Java – 集合框架完全解析
全栈程序员站长
2022/07/01
8330
java详细学习路线及路线图
Android工程师面试字节力扣刷题没有针对性?常见数据结构与算法面试题合集整出来了!
对于移动开发者来说,面试字节跳动最重要出了Android相关的面试题外算法是最重要的,而字节也非常喜欢在每面的最后问几个算法相关的问题,很多Android程序员苦恼找不到一份详细的算法面试题,接下来可以往下看看~
Android技术干货分享
2021/03/27
6280
Android工程师面试字节力扣刷题没有针对性?常见数据结构与算法面试题合集整出来了!
数据结构与算法-面试
栈是一种线性表,其限制只能在表尾进行插入或删除操作。由于该特性又称为后进先出的线性表。
知识浅谈
2022/02/27
7200
算法笔记汇总精简版下载_算法与数据结构笔记
10个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树; 10个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态 规划、字符串匹配算法。
全栈程序员站长
2022/09/20
1K0
数据结构-概述
线性表是具有相同数据类型的n个数据元素的有限序列。 逻辑上,每个元素有且只有一个直接前驱,有且只有一个直接后继(表头表尾元素例外)
千灵域
2022/06/17
1.7K0
数据结构-概述
10w字!前端知识体系+大厂面试总结(算法篇)
但是在两个月的算法练习中,第一次体会到编程不仅仅是技术,还是艺术,感受到了编程是一件很酷的事情
winty
2023/01/09
5770
10w字!前端知识体系+大厂面试总结(算法篇)
吴师兄导读:如何快速入门数据结构和算法
吴师兄导读:有哪些常见的数据结构?基本操作是什么?常见的排序算法是如何实现的?各有什么优缺点?本文简要分享算法基础、常见的数据结构以及排序算法,给同学们带来一堂数据结构和算法的基础课。
五分钟学算法
2020/08/21
1.7K0
吴师兄导读:如何快速入门数据结构和算法
重学数据结构和算法(二)之二叉树、红黑树、递归树、堆排序
最近学习了极客时间的《数据结构与算法之美]》很有收获,记录总结一下。 欢迎学习老师的专栏:数据结构与算法之美 代码地址:https://github.com/peiniwan/Arithmetic
六月的雨
2021/03/04
4870
《大话数据结构》总结第一章 绪论第二章 算法第三章 线性表第四章 栈和队列第五章 字符串第六章 树第七章 图第八章 查找第九章 排序
第一章 绪论 什么是数据结构? 数据结构的定义:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 第二章 算法 算法的特性:有穷性、确定性、可行性、输入、输出。 什么是好的算法? ----正确性、可读性、健壮性、时间效率高、存储量低 函数的渐近增长:给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n>N,f(n)总是比g(n)大,那么,我们说f(n)的增长渐近快于g(n)。于是我们可以得出一个结论,判断一个算法好不好,我们只通过少量的数据是不能做出准确判断的,如果我们可以
SeanCheney
2018/04/24
1.5K0
《大话数据结构》总结第一章 绪论第二章 算法第三章 线性表第四章 栈和队列第五章 字符串第六章 树第七章 图第八章 查找第九章 排序
数据结构和算法速记
目录 数据结构 算法 查找算法 排序算法 数据结构 数组 结构特征:内存地址连续,大小固定 使用特点:查询快,插入慢 链表 结构特征:内存地址不连续,大小可变 使用特点:查询慢,插入快 栈 结构特征:顺序栈(基于数组实现,继承数组特征),链式栈(基于链表实现,继承链表特征) 使用特点:先进后出,后进先出 队列 结构特征:顺序队列(基于数组实现,继承数组特征),链式队列(基于链表实现,继承链表特征) 使用特点:先进先出,后进后出 树 结构特征:每个节点有0个或多个子
Noneplus
2020/08/12
1.1K0
题库——————————————————————————
1、数据结构被形式地定义为(D,R),其中D是数据的_ 有限集合___,R是关系的有限集合。
用户10169043
2023/12/11
3610
如何理解并掌握 Java 数据结构
在Java里面常用的util有:String [],int [],ArrayList,Vector,CopyOnWriteArrayList等。及可以同过一维数组[]自己实现不同逻辑结构的Util类。而ArrayList封装了一些[]的基本操作方法。ArrayList和Vector的区别是:Vector是线程安全的,方法同步。CopyOnWriteArrayList也是线程安全的但效率要比Vector高很多。
IT小马哥
2020/03/18
5250
数据结构基础温故-6.查找(上):基本查找与树表查找
只要你打开电脑,就会涉及到查找技术。如炒股软件中查股票信息、硬盘文件中找照片、在光盘中搜DVD,甚至玩游戏时在内存中查找攻击力、魅力值等数据修改用来作弊等,都要涉及到查找。当然,在互联网上查找信息就更加是家常便饭。查找是计算机应用中最常用的操作之一,也是许多程序中最耗时的一部分,查找方法的优劣对于系统的运行效率影响极大。因此,本篇讨论一些查找方法。
Edison Zhou
2018/08/20
8360
数据结构基础温故-6.查找(上):基本查找与树表查找
《王道》数据结构笔记整理2022级_数据结构笔记整理
1.数据:数据是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别和处理的符号的集合。
全栈程序员站长
2022/09/22
3.2K0
《王道》数据结构笔记整理2022级_数据结构笔记整理
《大话数据结构》(二)
1.树(Tree)是n(n>=0)个结点的有限集。n=0时称为空树。在任意一颗非空树中:(1)有且仅有一个特定的称为根(Root)的结点;(2)当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1、T2……Tm,其中每一个集合本身又是一颗树,并且称为根的子树(SubTree)
硬核项目经理
2019/08/06
1.1K0
【愚公系列】软考中级-软件设计师 014-数据结构(考点简介)
数据结构是一种组织和存储数据的方式,它涉及如何在计算机中存储和访问数据的方法和技术。数据结构可以用来解决不同类型的问题,包括搜索、排序、插入和删除等操作。常见的数据结构包括数组、链表、栈、队列、树、图等。不同的数据结构有不同的特点和适用场景,选择合适的数据结构可以提高算法的效率和性能。
愚公搬代码
2024/01/26
5182
这是一份全面&详细的数据结构、算法学习指南
对于不同的查找需求场景,会采用不同的查找类型,最终采用的查找方式(查找算法)也有所不同,具体如下
Carson.Ho
2021/12/06
1.7K0
这是一份全面&详细的数据结构、算法学习指南
数据结构与算法(二)
排序与搜索 排序算法(英语:Sorting algorithm)是一种能将一串数据依照特定顺序进行排列的一种算法。 排序算法的稳定性 稳定性:稳定排序算法会让原本有相等键值的纪录维持相对次序。也就是如果一个排序算法是稳定的,当有两个相等键值的纪录R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前。 当相等的元素是无法分辨的,比如像是整数,稳定性并不是一个问题。然而,假设以下的数对将要以他们的第一个数字来排序。 (4, 1) (3, 1) (3, 7)(5, 6) 在这个状况下,有
酱紫安
2018/04/16
9240
数据结构与算法(二)
408-数据结构
第1讲 时间复杂度、矩阵展开 一、时间、空间复杂度 只考虑次数,不考虑常数。常见复杂度有:O(1)、O(n)、O(sqrt(n))、O(n^k)、O(logn)、O(nlogn) 考题:2011-1、2012-1、2013-1、2014-1、2017-1、2019-1 二、矩阵展开 矩阵的按行展开、按列展开,展开后下标从0开始。 考题:2016-4、2018-3、2020-1
她的店里只卖樱花
2022/11/15
3800
数据结构、算法
循环队列设front和rear两个指针,元素个数=(front-rear+Maxsize)%Maxsize
esse LL
2024/04/12
1760
推荐阅读
相关推荐
java详细学习路线及路线图
更多 >
交个朋友
加入HAI高性能应用服务器交流群
探索HAI应用新境界 共享实践心得
加入[游戏服务器] 腾讯云官方交流站
游戏服运维小技巧 常见问题齐排查
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验