GitHub Copilot --Your AI pair programmer
一、介绍 GitHub Copilot是一种基于人工智能的代码自动补全工具,由GitHub和OpenAI联合开发。它可以根据上下文和注释,生成代码片段和函数,帮助开发者快速编写代码。 GitHub Copilot是通过机器学习技术实现的。 它的工作原理是,通过分析开发者的代码库,学习代码的语法和结构,并生成与当前上下文相关的代码建议。它可以同时处理多种编程语言,包括Java、Python、JavaScript、TypeScript、Ruby、Golang等。开发者可以在编辑器中直接使用GitHub Copilot,它会自动提示代码片段和函数,大大提高了开发效率。二、GitHub Copilot的功能 - 代码自动生成 - 代码补全 - 代码提示三、如何使用GitHub Copilot 1. 访问 https://github.com/features/copilot/ ,安装GitHub Copilot:在VS Code编辑器中搜索安装GitHub Copilot插件,并按照提示进行安装,其他编辑器类似。 2. 配置编辑器:在安装完GitHub Copilot插件后,需要进行相关配置。你需要在VS Code的设置中,将“editor.suggestSelection”设置为“first”,以便在输入代码时,GitHub Copilot的代码建议优先显示。此外,你还可以根据需要进行其他相关设置。 3. 使用GitHub Copilot:在编辑器中输入代码时,GitHub Copilot会自动提示代码片段和函数,你可以选择使用或者忽略。如果你选择使用,GitHub Copilot会自动补全代码,并根据上下文和注释生成相应的代码。如果你不满意生成的代码,可以通过修改代码或者提供更多的上下文来改进生成结果。 四、GitHub Copilot限制 1. 代码生成的准确性:GitHub Copilot的代码生成基于机器学习,它需要大量的数据和算法模型来进行训练和优化。然而,由于训练数据的限制和算法模型的不完善,GitHub Copilot生成的代码可能存在一定的准确性问题,需要人工进行修正和调整。 2. 缺乏创造性:GitHub Copilot只能根据已有的代码片段和函数,生成与当前上下文相关的代码建议。它缺乏创造性和创新性,无法像人类开发者一样,通过思考和创造来解决复杂的问题。 3. 安全性问题:由于GitHub Copilot是基于机器学习的技术,它需要训练数据来进行学习和优化。然而,训练数据可能包含敏感信息或机密代码,如果不加以保护,可能会导致安全性问题。 4. 版权和知识产权问题:GitHub Copilot的代码生成可能涉及到版权和知识产权问题。如果生成的代码涉及到他人的版权或知识产权,可能会引发法律纠纷和争议。 5. 依赖于互联网:GitHub Copilot需要连接互联网才能进行学习和优化。如果没有良好的互联网连接,可能会影响其性能和准确性。 6. 收费,个人每月10美元,每年100美元的价格,对大多数人来说存在门槛。 总的来说,GitHub Copilot虽然是一种非常有前途的技术,但也存在一些限制和局限性。在使用GitHub Copilot时,需要注意这些限制和局限性,并进行必要的修正和调整,以确保生成的代码的准确性和安全性五、总结 1. 提高软件开发效率:GitHub Copilot可以根据上下文和注释,生成与当前上下文相关的代码建议,帮助开发者快速编写代码。这将大大提高软件开发的效率,减少开发者的重复劳动和错误率。 2. 降低软件开发门槛:GitHub Copilot可以自动生成代码,使得软件开发的门槛降低,即使是没有编程经验的人也可以快速编写代码。这将有助于推动软件开发的普及和发展。 3. 挑战传统软件开发模式:GitHub Copilot的出现挑战了传统的软件开发模式,即由开发者手动编写代码。未来,随着人工智能技术的不断发展,自动化代码生成的比例可能会越来越高,从而改变软件开发的方式和模式。 4. 面临法律和道德问题:GitHub Copilot的代码生成基于机器学习,可能会涉及到版权、知识产权等法律和道德问题。未来,相关法律和政策的制定和完善将对GitHub Copilot的发展产生重要影响。 总的来说,GitHub Copilot是一种具有潜在影响的技术,它将对软件开发产生重要影响。未来,随着人工智能技术的不断发展,GitHub Copilot的功能和应用场景可能会不断扩展,我们需要密切关注其发展趋势和影响。
查看详情点赞2评论1收藏1浏览822023-06-27 11:12:53RSA加密与签名有什么区别
区别:RSA加密:RSA密码体制是一种公钥密码体制,加密算法公开,以分配的密钥作为加密解密的关键。RSA签名:签名就是在这份资料后面增加一段强而有力的证明,以此证明这段信息的发布者和这段信息的有效性完整性。在使用RSA进行通讯的时候,一般是两者结合,即:加密>签名>解密>验签公钥加密、私钥解密、私钥签名、公钥验签。加密是可逆的,而签名是不可逆的我们可以对一份资料用公钥加密,再用私钥解密,但我们对这份资料进行签名则是不可逆的,因为哈希本身是不可逆的。加密和签名都涉及到了使用公钥加密,前者加密了信息,后者加密了信息的hash加密和签名都是为了安全性考虑,但略有不同。加密是为了防止信息被泄露,而签名是为了防止信息被篡改。为什么签名是对信息hash之后加密,而不是加密一些特定的字符?这是因为防止中间人尝试向私钥拥有者反复发送一些特定的字符,得到加密后的信息,达到破解或者伪造之类的目的。所以用私钥随便加密信息是不安全的。RSA的签名与加密一般用在需要非常安全的环境下,例如支付总结:签名的本质其实就是加密,但是由于签名无需还原成明文,因此可以在加密前进行哈希处理。所以签名其实就是哈希+加密,而验签就是哈希+解密+比较。签名过程:对明文做哈希,拼接头信息,用私钥进行加密,得到签名。验签过程:用公钥解密签名,然后去除头信息,对明文做哈希,比较2段哈希值是否相同,相同则验签成功。
查看详情点赞1评论收藏浏览362023-06-27 10:07:20Gin框架系列教程(3)- go-mod包管理
(从 0-1 搭建你的Gin框架后台系统)go版本>=1.11一、什么是module?go中包管理工具二、使用module和不使用的区别使用环境变量中的GO111MODULE控制是否使用mod1.开启mod:go env -w GO111MODULE=on,会将包下载到gopath下的pkg下的mod文件夹中2.关闭mod:go env -w GO111MODULE=off,会将包下载到gopath下的src下3.go env GO111MODULE=auto,只有当当前目录在GOPATH/src目录之外而且当前目录包含go.mod文件或者其子目录包含go.mod文件才会启用。项目可以不用建在src下了,任何非中文路径下都可以,建议有个统一的代码路径三、go.mod文件的语法介绍go help go.mod 查看帮助示例:module my/thing go 1.13.4 require ( new/thing v2.3.4 old/thing v1.2.3 ) 1.module:指明根目录2.go 后面跟版本号是指定go的版本2.require是个动作指令,对依赖包起作用,比如require(依赖),还有exclude(排除),replace(替代),相同动作的可以放在一个动词+括号组成的结构中,如下:require ( new/thing v2.3.4 old/thing v1.2.3 ) require new/thing v2.3.4 require old/thing v1.2.3 // 排除 exclude old/thing v1.2.3 // 替换,使用箭头后的替换前面的 replace bad/thing v1.4.5 => good/thing v1.4.5 注意:exclude和replace仅适用于主的go.mod文件中,其他的依赖中会被忽略、可以使用replace替换无法获取的库,3.注释:使用//,没有/* xxx */这种块注释四、go mod 命令go mod help 查看帮助download 下载模块到本地缓存,go env中的GOCACHE路径,可以通过go clean -cache清空缓存 多个项目可以共享缓存的包 edit 在工具或脚本中编辑go.mod文件 graph 打印模块需求图 init 在当前目录下初始化新的模块 go mod init 【项目名】 默认使用当前路径的项目名称 tidy 添加缺失的模块以及移除无用的模块,生成go.sum文件 vendor 会自动下载项目中依赖的包到项目根目录下的vendor文件夹下,并写入go.mod文件,同时生成 modules.txt文件 go mod vender -v verify 检查当前模块的依赖是否全部下载下来,是否下载下来被修改过 why 解释为什么需要包或模块 注意:-v参数可以查看执行的详细信息 已经完成的项目可以这样操作来使用mod项目路径下执行go mod init然后再执行go mod vendor(或者直接运行项目)项目中可以是这样的执行顺序:init初始化 --> tidy 增删模块--> verify 校验模块-->vendor注意:项目中引入该项目下的任何路径都要是绝对路径,也就是以改项目名开头的路径使用mod的步骤:1.开启mod:go111module=on2.进入项目,执行go mod init (在项目根目录生成go.mod文件)3.启动项目(go.mod添加依赖的包)
查看详情点赞评论收藏浏览432023-06-19 16:53:29Gin框架系列教程(2)- Gin的第一次,hello world!
(从 0-1 搭建你的Gin框架后台系统)我们先新建一个文件,gin_demo,然后初始化一个go项目,我们用go mod来管理包,之后我们讲一下什么是modgo mod init gin_demo接下来新建main.go文件,引入Gin,开始第一个项目package main import "github.com/gin-gonic/gin" func main() { // g:=gin.New() g := gin.Default() g.GET("/", func(c *gin.Context) { c.String(200, "hello world") }) g.Run(":9000") }运行项目:go run main我们的第一个Gin项目就可以了。运行原理一、router:=gin.Default()初始化一个引擎,是gin.New()的升级二、router.GET1.RESTFUL风格的请求方法(method)2.有两个参数:relativePath:路由,string类型HandlerFunc:执行的函数3.可以使用router.Handle代替,多了个的method参数(字符串),method参数必须是大写的,如:GET三、执行的函数1.必须有个参数是gin.Context指针类型的注意:context是gin的一个重要组成部分。用来在中间层传递数据流。2.函数是个参数,不能调用四、router.Run启动http监听,有个address参数,字符串类型的,可以指定host和port注意:addr的host和port是用冒号分隔的只指定port,port前面必须要有冒号指定了host和port,host和port中间有冒号不能只指定hostg.Run(":9000")
查看详情点赞评论收藏浏览332023-06-19 16:49:00Gin框架系列教程(1)- gin框架介绍,环境搭建
(从 0-1 搭建你的Gin框架后台系统)一、gin框架介绍Gin 是一个用 Go (Golang) 编写的 web 框架。它是一个类似于 martini 但拥有更好性能的 API 框架,由于 httprouter,速度提高了近 40 倍,简单易用,是一个轻量级框架。如果你是性能和高效的追求者,你会爱上 Gin。二、为什么选择gin1.运行响应非常快2.快速开发3.文档齐全4.社区活跃三、特性1.快速:基于 Radix 树的路由,小内存占用。没有反射。可预测的 API 性能。2.支持中间件:传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如:Logger,Authorization,GZIP,最终操作 DB。3.Crash 处理:Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样,你的服务器将始终可用。例如,你可以向 Sentry 报告这个 panic!4.JSON 验证:Gin 可以解析并验证请求的 JSON,例如检查所需值的存在。5.路由组:更好地组织路由。是否需要授权,不同的 API 版本…… 此外,这些组可以无限制地嵌套而不会降低性能。6.错误管理:Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终,中间件可以将它们写入日志文件,数据库并通过网络发送。7.内置渲染:Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API。8.可扩展性:新建一个中间件非常简单gin环境搭建注意:go1.9版本以上,很快将不再支持go1.7或go1.8。一、go环境安装1.go安装下载地址: https://go.dev/dl/这里选择你需要下载的版本,现在最新版是1.20.5,可以自己选择需要的版本。windows,和linux的安装方法稍有差异,不过大同小异,网上有很多方法,不过多介绍,可以多参考网上。这里我们直接安装windows版本(go1.19.4)。然后,我们安装windows软件一样,傻瓜式操作,直接下一步,下一步到底。2.环境配置:变量名:GOPATH 变量值:E:\go\workspace 你的工作路径变量名:GOROOT 变量值:E:\go\install go的安装路径变量名:Path 增加值:%GOROOT%\bin;%GOPATH%\bin;注意:删除自动添加的gopath和goroot注意添加完GOPATH,GOROOT两个变量值,还需要添加他们下面的bin执行目录。3.检查配置是否成功go env 查看GOPATH和GOROOT是否正确然后就可以看到安装的目录和版本是否正确,当显示下面截图,我们就安装成功了。二、工程管理:工作目录下新建三个文件夹1.src:用于以代码包的形式组织并保存go源码文件,2.pkg:用于存放经由go install命令构建的安装后的代码包,不需要手动创建3.bin:与pkg目录类似,在通过go install命令完成安装后,保存由go命令源码间生成的可执行文件三、安装gingin的安装就很简单了,直接命令拉取。go get -u github.com/gin-gonic/gin五、安装编辑工具(goland,vscode等都可以,看自己喜欢)第一节我们就到这里结束了,接下来我们就开始gin框架吧。hello world
查看详情点赞评论收藏浏览592023-06-19 15:36:49JS 生成二维码
JS生成二维码,其实很容易。下面我们来测试一下,一些简单的二维码就用JS生成。我们用一个生成二维码的库: https://github.com/SumiMakito/Awesome-qr.js 在网上翻了一些资料,这个库是没有什么缺点的,当然也可以尝试用其他生成二维码的库。html引入Awesome-qr库:<script src='./qr/dist/awesome-qr.js' type="text/javascript"></script> <script src="http://www.alingfeng.cn/js/jquery.min.js"></script>生成二维码:<img id="qrcodeimg"/ > <script> var creatqrcode = function (text, logo, background) { // 二维码生成参数 var text = "http://www.alingfeng.cn"; var size = 200; var colorDark = "#000000"; var margin = 9 var background = background || "#ffffff"; var logo = logo || ""; $("#qrcodeimg").css({width:size+"px",height:size+"px"}) new AwesomeQR.AwesomeQR({ text: text, // 内容 size: size, // 二维码大小 margin: margin, // 二维码白边大小 colorDark:colorDark, // 二维码颜色 colorLight: "rgba(159,255,255,0)", // 二维码背景颜色 logoImage : logo, // 二维码中间logo logoScale : 0.3, // 二维码中间logo大小 logoCornerRadius : 0, // 二维码中间logo圆角 }).draw() .then((dataURL) => { $("#qrcodeimg").attr("src", dataURL) }) .catch((err) => { console.error(err); }); } $(function(){ // 初始化生成二维码 creatqrcode("http://www.alingfeng.cn") }) </script>然后生成二维码试试:
查看详情点赞1评论收藏浏览882023-06-17 10:56:44学习node+websocket+vue3搭建多人聊天室
跟着做小白都能做出来~~首先搭建前端Vite 项目兼容性注意Vite 需要 Node.js 版本 14.18+,16+。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。使用 npm或yarn、pnpm任意安装,个人推荐pnpm,原因如下快速:pnpm比传统方案(yarn, npm)安装包的速度快了两倍,甚至比yarn2,pnp模式还要快更严格高效:node_modules 中的文件是从一个单一的可内容寻址的存储中链接过来的,代码无法访问任意包monorepo:天然内置支持当仓库多包$ npm create vite@latest $ yarn create vite $ pnpm create vite1.安装并输入项目名称2.这里选择vue3.根据个人选择,这里选择js4.到这里就成功快速搭建完成vite3+vue3前端基础框架了,跟着下面的命令执行即可在vsocde编辑器中打开打开src目录,建立以下模块结构首先cofigjs这里是用来统一管理地址的,后期维护也方便只需要修改地址即可1.congfig-index.js中,这里写的是websokct// 域名地址(项目实地址)这里写的是本地的地址 const BASE_URL='127.0.0.1' // 端口号 const WS_PORT='8000' // WebSocket协议的URL export const WS_ADDRESS=`ws://${BASE_URL}:${WS_PORT}`这里的hooks是vue3借鉴的react函数式组件的优点2.hooks-index.js// 这里的index.js文件用于统一引用导出hooks的方法。更规范 import useWebSocket from './websocket' export { useWebSocket }hooks-websocket.js// 引用config-index.js封装好的WebSocket协议的URL import { WS_ADDRESS } from "../configs" // 封装一个使用websocket的高阶函数 // 这里的handleMessage用于接收及发送的消息 function useWebSocket(handleMessage) { // 建立连接(创建WebSocket对象): // const ws = new WebSocket(url, [protocol]);// url:服务器端地址;protocol:可选,指定可接受的子协议。 const ws = new WebSocket(WS_ADDRESS) const init = () => { bindEvent() } init() function bindEvent() { // ws.onopen():连接建立时触发的事件 ws.addEventListener('open', handleOpen, false); // ws.onclose():关闭连接方法 ws.addEventListener('close', handleClose, false); // ws.onerror():通信发生错误时触发 ws.addEventListener('error', handleError, false); // ws.onmessage(): 客户端接收服务器端发送的信息时触发 ws.addEventListener('message', handleMessage, false); } function handleOpen(e) { console.log('WebSocket open', e) } function handleClose(e) { console.log('WebSocket close', e) } function handleError(e) { console.log('WebSocket error', e) } return ws } export default useWebSocket3.pages-home.vue建立简单的聊天页面<script setup> // onMounted:挂载完数据 // reactive:响应式数据,reactive 参数必须是对象 (json / arr) // toRaw:响应式转化普通对象 // toRefs:降reactive中的响应式结构为一个个的ref响应式数据 import { onMounted, reactive, toRaw, toRefs } from "vue"; // 引用全局路由对象useRouter import { useRouter } from "vue-router"; // 引用hooks中封装好的高阶函数,用于消息发送 import { useWebSocket } from '../hooks' // 这里useWebSocket(handleMessage)用于接收消息 const ws = useWebSocket(handleMessage) const router = useRouter() // 定义state用于接收和发送的消息 const state = reactive({ msg: '', msgList: [] }) // 结构state const { msg, msgList } = toRefs(state) // 获取用户名,没有就跳转到登录页 let username = '' onMounted(() => { username = localStorage.getItem('username') if (!username) { router.push('/login') return } }) // 发送消息按钮 const sendMsg = () => { if (msg.length < 1) { return } // ws.send():发送信息的方法 // 由于后台接收的是JSON类型,这里发送的消息需要JSON.stringify ws.send(JSON.stringify({ id: new Date().getTime(), user: localStorage.getItem('username'), dateTime: new Date().getTime(), // 这里必须让msg失去响应式或深拷贝该值,否则造成发送的消息根据再次输入的消息发生变更 msg: toRaw(msg.value), })) // 发送完清空消息框 msg.value = '' } // 用于接收发送过来的消息 function handleMessage(e) { // 由于后台接收的是JSON类型,这里发送的消息需要JSON.parse const msgData = JSON.parse(e.data) // 向列表添加每条聊天消息 msgList.value.push(msgData) } </script> <template> <div> <ul> <li v-for="item in msgList" :key="item.id"> <p>用户名:{{ item.user }}</p> <p>{{ new Date(item.dateTime) }}</p> <p>消息:{{ item.msg }}</p> </li> </ul> <input type="text" placeholder="请输入消息" v-model="msg"> <button @click="sendMsg">发送</button> </div> </template> <style scoped> li p { text-align: left; } </style> pages-login.vue进入聊天室的页面<template> <div> <input type="text" placeholder="请输入用户名" v-model="userName"> <button @click="enterSocket">进入聊天室</button> </div> </template> <script setup> import { onMounted, ref } from "vue"; import { useRouter} from 'vue-router' const router=useRouter() const userName=ref('') onMounted(()=>{ userName.value=localStorage.getItem('username') // 简单的判断是否已进入聊天室 if(userName.value){ router.push('/home') return } }) // 进入聊天室 const enterSocket=()=>{ if(userName.value<6){ alert('用户名不小于6位') return } localStorage.setItem('username',userName.value) userName.value='' router.push('/home') } </script>4.router-index.js 由于框架是没有自带router的这里需要去pnpm i vue-router安装下import { createRouter, createWebHashHistory } from "vue-router"; import routes from "./router"; const router = createRouter({ history: createWebHashHistory(), routes, }); export default router;router-router.jsimport login from "../pages/login.vue"; // 路由列表 let routes= [ { path: "/login", name: "login", component: login, }, { path: "/home", name: "home", component: () => import("../pages/home.vue"), children: [], }, ]; export default routes; 5.App.vue<template> <router-view></router-view> </template> 6.main.jsimport { createApp } from 'vue' import './style.css' import App from './App.vue' import router from "./router"; createApp(App).use(router).mount('#app') 6.在当前目录下新建server目录,用于node服务进入server目录生成package.json然后安装包在安装websocket的插件wx接着是node的目录如一下就完成在package.json中配置启动命令如index.js中写// 使用CommonJS require引入 // CommonJS 中的 require/exports 和 ES6 中的 import/export 区别 // CommonJS 模块是运行时加载,ES6 Modules 是编译时加载并输出接口。 // CommonJS 输出是值的拷贝;ES6 Modules输出的是值的引用,被输出模块的内部的改变会影响引用的改变。 // CommonJs 导入的模块路径可以是一个表达式,因为它使用的是 require() 方法,甚至这个表达式计算出来的内容是错误的路径,也可以通过编译到执行阶段再出错; // 而ES6 Modules 只能是字符串,并且路径不正确,编译阶段就会抛错。 // CommonJS this 指向当前模块,ES6 Modules this 指向 undefined // ES6 Modules 中没有这些顶层变量:arguments、require、module、exports、__filename、__dirname const Websocket=require('ws') ;((Ws)=>{ // 建立ws服务地址,这里跟前端都类似了唯一的区别是connection和message(连接和消息) const server=new Ws.Server({port:8000,host:"0.0.0.0"}) const init=()=>{ bindEvent() } function bindEvent(){ server.on('open',function(event){ server.send('OpenBarScanner') }) server.on('close',handelClose) server.on('error',handelError) server.on('connection',handelConnection) } function handelOpen(){ console.log('handelOpen') } function handelClose(){ console.log('handelClose') } function handelError(){ console.log('handelError') } // 连接时提示消息并发送到客户端 function handelConnection(ws){ console.log('WebSocket Connection') ws.on('message',handelMessage) } // 用于接收发送的消息 function handelMessage(msg){ server.clients.forEach((c)=>{ // 由于node发送到客户端的消息是Blob类型,这里需要用Buffer.form().toString()转化为utf8类型识别消息 c.send(Buffer.from(msg).toString('utf8')) }) } init() })(Websocket)
查看详情点赞2评论1收藏1浏览822023-06-15 15:25:03go 8个常用排序测试(冒泡排序,插入排序,选择排序,希尔排序,堆排序,基数排序,快速排序,计数排序)
前两天在做项目的时候,用到了排序,在网上查阅了一些资料做了部分对比,所以对常用的排序做了一些对比。当然不是全部,例如归并排序,二叉树之类的。等以后有时间可以了解一下。下面我们就了解一下这些排序;首先,我们先生成100位随机数字,然后对这一组数字进行排序。package main import ( "fmt" "math" mathRand "math/rand" "time" ) func main() { // 生成随机数 mathRand.Seed(time.Now().UnixNano()) var arr [100]int // 不重复生成 for i := 0; i < 100; i++ { arr[i] = mathRand.Intn(100) loop: for k := 0; k < i; k++ { if arr[k] == arr[i] { arr[i] = mathRand.Intn(100) goto loop } } } //打印随机数据 fmt.Println("生成的随机数切片:\n", arr) }1、冒泡排序// 冒泡排序方法 func mpArr(data [100]int) [100]int { var arrx int for i := 0; i < len(data)-1; i++ { for j := 0; j < len(data)-i-1; j++ { arrx++ if data[j] > data[j+1] { //交换 data[j], data[j+1] = data[j+1], data[j] } } } fmt.Println("冒泡排序排序次数", arrx) return data } mpArr := mpArr(arr) fmt.Println("冒泡排序之后的切片", mpArr)我们可以看到冒泡排序是比较稳定的。2、插入排序// 插入排序 func insertSort(data [100]int) [100]int { var j int var pxNum int for i := 1; i < len(data); i++ { temp := data[i] for j = i; j > 0 && temp < data[j-1]; j-- { data[j] = data[j-1] pxNum++ } data[j] = temp } fmt.Println("改进版插入排序次数:", pxNum) return data } // 改进版插入排序 func InsertionSort2(arr [100]int) [100]int { n := len(arr) var pxNum int for i := 1; i < n; i++ { // 无序区 tmp := arr[i] left, right := 0, i-1 for left <= right { pxNum++ mid := (left + right) / 2 if arr[mid] > tmp { right = mid - 1 } else { left = mid + 1 } } j := i - 1 for ; j >= left; j-- { // 有序区 arr[j+1] = arr[j] pxNum++ } arr[left] = tmp } fmt.Println("插入排序次数:", pxNum) return arr } // 使用插入排序 cr2Arr := InsertionSort2(arr) fmt.Println("插入排序之后的切片", cr2Arr) // 使用改进版插入排序 crArr := insertSort(arr) fmt.Println("改进版插入排序之后的切片", crArr)我们可以看到插入排序也是比较稳定的。3、选择排序// 选择排序 func SelectionSort(arr [100]int) [100]int { var pxNum int n := len(arr) for i := 0; i < n-1; i++ { minNumIndex := i // 无序区第一个 for j := i + 1; j < n; j++ { if arr[j] < arr[minNumIndex] { minNumIndex = j pxNum++ } } arr[i], arr[minNumIndex] = arr[minNumIndex], arr[i] } fmt.Println("选择排序次数:", pxNum) return arr } // 使用选择排序 xzArr := SelectionSort(arr) fmt.Println("选择排序之后的切片", xzArr)由此可以看出,选择排序是不稳定的4、希尔排序// 希尔排序 func shellSort(data [100]int) [100]int { var j int var pxNum int for h := len(data) / 2; h > 0; h /= 2 { //外层循环控制步长 for i := h; i < len(data); i++ { //内层循环是对步长个子切片做插入排序 temp := data[i] for j = i; j >= h && temp < data[j-h]; j -= h { data[j] = data[j-h] pxNum++ } data[j] = temp } } fmt.Println("希尔排序次数:", pxNum) return data } xrArr := shellSort(arr) fmt.Println("希尔排序之后的切片", xrArr)希尔排序也是不稳定的5、堆排序// 堆排序 func heapSort(data [100]int) [100]int { m := len(data) var pxNum int s := m / 2 for i := s; i >= 0; i-- { heap(data, i, m-1) } for i := m - 1; i > 0; i-- { data[i], data[0] = data[0], data[i] heap(data, 0, i-1) pxNum++ } fmt.Println("堆排序次数:", pxNum) return data } dArr := heapSort(arr) fmt.Println("堆排序之后的切片", dArr)堆排序也是不稳定的6、基数排序// 基数排序 func RadixSort(arr [100]int) [100]int { var pxNum int maxn := maxBitNum(arr) // arr最大位数 dev := 1 // 除数,保证商最后一位是我们想要的 mod := 10 // 模,取商的最后一位 for i := 0; i < maxn; i++ { // 进行maxn次排序 bucket := make([][]int, 10) // 定义10个空桶 result := make([]int, 0) // 存储中间结果 for _, v := range arr { n := v / dev % mod // 取出对应位的值,放入对应桶中 bucket[n] = append(bucket[n], v) pxNum++ } dev *= 10 // 按顺序存入中间切片 for j := 0; j < 10; j++ { result = append(result, bucket[j]...) pxNum++ } // 转存到原切片(结果) for k := range arr { arr[k] = result[k] pxNum++ } } fmt.Println("基数排序次数:", pxNum) return arr } zsArr := RadixSort(arr) fmt.Println("基数排序之后的切片", zsArr)基数排序是稳定的。7、快速排序// 快速排序 func QuickSort(left int, right int, array *[100]int) { l := left r := right // pivot 是中轴, 支点 pivot := array[(left+right)/2] temp := 0 // for 循环的目标是将比 pivot 小的数放到左边,比 pivot 大的数放到右边 for l < r { // 从 pivot 的左边找到大于等于pivot的值 for array[l] < pivot { l++ } // 从 pivot 的右边边找到小于等于pivot的值 for array[r] > pivot { r-- } // 1 >= r 表明本次分解任务完成, break if l >= r { break } // 交换 temp = array[l] array[l] = array[r] array[r] = temp // 优化 if array[l] == pivot { r-- } if array[r] == pivot { l++ } } // 如果 1== r, 再移动下 if l == r { l++ r-- } // 向左递归 if left < r { QuickSort(left, r, array) } // 向右递归 if right > l { QuickSort(l, right, array) } } ksArr := arr QuickSort(0, len(ksArr)-1, &ksArr) fmt.Println("快速排序之后的切片", ksArr)快排也是不稳定的。8、计数排序// 计数排序 func CountingSort(arr [100]int) [100]int { var pxNum int length := len(arr) maxValue := getMaxValue(arr) bucketLen := maxValue + 1 bucket := make([]int, bucketLen) sortedIndex := 0 // 统计每个元素出现的个数 for i := 0; i < length; i++ { bucket[arr[i]] += 1 pxNum++ } // 按照统计结果写入arr for j := 0; j < length; j++ { for bucket[j] > 0 { pxNum++ arr[sortedIndex] = j // bucket[j]的值是统计结果,后面会变化,j是真正值 sortedIndex++ bucket[j]-- } } fmt.Println("计数排序次数:", pxNum) return arr } jsArr := CountingSort(arr) fmt.Println("计数排序之后的切片", jsArr)计数排序也是稳定的 稳定的排序算法有:冒泡排序、插入排序、计数排序、基数排序。 不稳定的排序算法有:选择排序、希尔排序、快速排序、堆排序。 当然每个排序方法只有最适合的场景,不能单从稳定性考虑,也要从性能上考虑,不能一概而论。
查看详情点赞1评论收藏浏览652023-06-14 09:58:31《千字文》全文,儿童启蒙必备。
《千字文》为南朝周兴嗣所编,它的撰作,相传还有一段故事;原来是当年梁武帝令殷铁石在王羲之书写的碑文中拓下不重复的一千个字,供皇子们学书用的。但由于字字孤立,互不联属,所以他又召来周兴嗣嘱道:“卿有才思,为我韵之。”周兴嗣只用了一个晚上就编好进呈武帝。这便是传至今日的《千字文》。周兴嗣的《千字文》精思巧构,知识丰瞻,音韵谐美,宜蒙童记诵,故成为千百年蒙学教科书。天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。寒来暑往,秋收冬藏。闰余成岁,律吕调阳。云腾致雨,露结为霜。金生丽水,玉出昆冈。剑号巨阙,珠称夜光。果珍李柰,菜重芥姜。海咸河淡,鳞潜羽翔。龙师火帝,鸟官人皇。始制文字,乃服衣裳。推位让国,有虞陶唐。吊民伐罪,周发殷汤。坐朝问道,垂拱平章。爱育黎首,臣伏戎羌。遐迩一体,率宾归王。鸣凤在竹,白驹食场。化被草木,赖及万方。盖此身发,四大五常。恭惟鞠养,岂敢毁伤。女慕贞洁,男效才良。知过必改,得能莫忘。罔谈彼短,靡恃己长。信使可覆,器欲难量。墨悲丝染,诗赞羔羊。景行维贤,克念作圣。德建名立,形端表正。空谷传声,虚堂习听。祸因恶积,福缘善庆。尺璧非宝,寸阴是竞。资父事君,曰严与敬。孝当竭力,忠则尽命。临深履薄,夙兴温凊。似兰斯馨,如松之盛。川流不息,渊澄取映。容止若思,言辞安定。笃初诚美,慎终宜令。荣业所基,籍甚无竟。学优登仕,摄职从政。存以甘棠,去而益咏。乐殊贵贱,礼别尊卑。上和下睦,夫唱妇随。外受傅训,入奉母仪。诸姑伯叔,犹子比儿。孔怀兄弟,同气连枝。交友投分,切磨箴规。仁慈隐恻,造次弗离。节义廉退,颠沛匪亏。性静情逸,心动神疲。守真志满,逐物意移。坚持雅操,好爵自縻。都邑华夏,东西二京。背邙面洛,浮渭据泾。宫殿盘郁,楼观飞惊。图写禽兽,画彩仙灵。丙舍旁启,甲帐对楹。肆筵设席,鼓瑟吹笙。升阶纳陛,弁转疑星。右通广内,左达承明。既集坟典,亦聚群英。杜稿钟隶,漆书壁经。府罗将相,路侠槐卿。户封八县,家给千兵。高冠陪辇,驱毂振缨。世禄侈富,车驾肥轻。策功茂实,勒碑刻铭。盘溪伊尹,佐时阿衡。奄宅曲阜,微旦孰营。桓公匡合,济弱扶倾。绮回汉惠,说感武丁。俊义密勿,多士实宁。晋楚更霸,赵魏困横。假途灭虢,践土会盟。何遵约法,韩弊烦刑。起翦颇牧,用军最精。宣威沙漠,驰誉丹青。九州禹迹,百郡秦并。岳宗泰岱,禅主云亭。雁门紫塞,鸡田赤诚。昆池碣石,钜野洞庭。旷远绵邈,岩岫杳冥。治本于农,务兹稼穑。俶载南亩,我艺黍稷。税熟贡新,劝赏黜陟。孟轲敦素,史鱼秉直。庶几中庸,劳谦谨敕。聆音察理,鉴貌辨色。贻厥嘉猷,勉其祗植。省躬讥诫,宠增抗极。殆辱近耻,林皋幸即。两疏见机,解组谁逼。索居闲处,沉默寂寥。求古寻论,散虑逍遥。欣奏累遣,戚谢欢招。渠荷的历,园莽抽条。枇杷晚翠,梧桐蚤凋。陈根委翳,落叶飘摇。游鹍独运,凌摩绛霄。耽读玩市,寓目囊箱。易輶攸畏,属耳垣墙。具膳餐饭,适口充肠。饱饫烹宰,饥厌糟糠。亲戚故旧,老少异粮。妾御绩纺,侍巾帷房。纨扇圆洁,银烛炜煌。昼眠夕寐,蓝笋象床。弦歌酒宴,接杯举殇。矫手顿足,悦豫且康。嫡后嗣续,祭祀烝尝。稽颡再拜,悚惧恐惶。笺牒简要,顾答审详。骸垢想浴,执热愿凉。驴骡犊特,骇跃超骧。诛斩贼盗,捕获叛亡。布射僚丸,嵇琴阮箫。恬笔伦纸,钧巧任钓。释纷利俗,并皆佳妙。毛施淑姿,工颦妍笑。年矢每催,曦晖朗曜。璇玑悬斡,晦魄环照。指薪修祜,永绥吉劭。矩步引领,俯仰廊庙。束带矜庄,徘徊瞻眺。孤陋寡闻,愚蒙等诮。谓语助者,焉哉乎也。
查看详情点赞评论收藏浏览742023-06-13 16:45:17《百家姓》全文,前百排名!
2023年百家姓全文:赵钱孙李 周吴郑王 冯陈褚卫 蒋沈韩杨朱秦尤许 何吕施张 孔曹严华 金魏陶姜戚谢邹喻 柏水窦章 云苏潘葛 奚范彭郎鲁韦昌马 苗凤花方 俞任袁柳 酆鲍史唐费廉岑薛 雷贺倪汤 滕殷罗毕 郝邬安常乐于时傅 皮卞齐康 伍余元卜 顾孟平黄和穆萧尹 姚邵湛汪 祁毛禹狄 米贝明臧计伏成戴 谈宋茅庞 熊纪舒屈 项祝董梁杜阮蓝闵 席季麻强 贾路娄危 江童颜郭梅盛林刁 钟徐邱骆 高夏蔡田 樊胡凌霍虞万支柯 昝管卢莫 经房裘缪 干解应宗丁宣贲邓 郁单杭洪 包诸左石 崔吉钮龚程嵇邢滑 裴陆荣翁 荀羊於惠 甄曲家封芮羿储靳 汲邴糜松井段富巫 乌焦巴弓牧隗山谷 车侯宓蓬全郗班仰 秋仲伊宫宁仇栾暴 甘钭厉戎 祖武符刘 景詹束龙叶幸司韶 郜黎蓟薄 印宿白怀 蒲邰从鄂索咸籍赖 卓蔺屠蒙 池乔阴郁 胥能苍双闻莘党翟 谭贡劳逄 姬申扶堵 冉宰郦雍却璩桑桂 濮牛寿通 边扈燕冀 郏浦尚农温别庄晏 柴瞿阎充 慕连茹习 宦艾鱼容向古易慎 戈廖庾终 暨居衡步 都耿满弘匡国文寇 广禄阙东 欧殳沃利 蔚越夔隆师巩厍聂 晁勾敖融 冷訾辛阚 那简饶空曾毋沙乜 养鞠须丰 巢关蒯相 查后荆红游竺权逯 盖益桓公 万俟司马 上官欧阳(复姓)夏侯诸葛 闻人东方(复姓)赫连皇甫 尉迟公羊(复姓)澹台公冶 宗政濮阳(复姓) 淳于单于 太叔申屠(复姓)公孙仲孙 轩辕令狐(复姓) 钟离宇文 长孙慕容(复姓)鲜于闾丘 司徒司空(复姓) 亓官司寇 仉督子车(复姓)颛孙端木 巫马公西(复姓) 漆雕乐正 壤驷公良(复姓)拓跋夹谷 宰父谷梁(复姓) 晋楚闫法 汝鄢涂钦段干百里 东郭南门(复姓) 呼延 归 海 羊舌 微生(有复姓)岳帅缑亢 况后有琴 梁丘左丘 东门西门(复姓)商牟佘佴 伯 赏 南宫(有复姓)墨哈谯笪 年爱阳佟第五 言 福(有复姓)《百家姓》终 中国人口最多姓氏前十排名: 1、王姓-占全中国汉族人口的 7.94%=101,300,000人。 2、张姓 -占全中国汉族人口的 7.41%=100,900,000人。 3、李姓 -占全中国汉族人口的 7.07%=95,800,000人。 4、刘姓 -占全中国汉族人口的' 5.38%=70,600,000人。 5、陈姓 -占全中国汉族人口的 4.53%=54,400,000人。 6、杨姓 -占全中国汉族人口的 3.08%=41,000,000人。 7、黄姓 -占全中国汉族人口的 2.29%=29,500,000人。 8、周姓 -占全中国汉族人口的 2.23%=26,800,000人。 9、胡姓 -占全中国汉族人口的 2.12%=25,400,000人。 10、赵姓-占全中国汉族人口的 2.05%=24,600,000人。 中国人口最多的前100名姓氏:前十名总人口约为5.5亿人。 11吴 12徐 13宋 14林 15朱 16孙17高 18曹 19郭 20马 21罗 22何23梁 24谢 25韩 26郑 27于 28唐 29董 30夏 31傅 32冯 33袁 34薛 35许 36姚 37彭 38曾 39汪 40江 41苏 42卢 43叶 44余 45肖 46魏47邓48谭 49阎 50丁 51潘 52杜 53戴 54毛 55钟 56廖57田 58任59姜 60范 61方 62贾 63蔡 64程 65沈 66邹 67熊 68金69陆 70郝 71孔 72白 73崔 74康 75吕 76邱 77秦 78蒋79石 80史 81顾 82侯 83邵 84孟 85龙 86 万 87段 88莫 89钱 90汤 91尹 92黎 93易 94常 95武 96乔 97贺 98赖 99龚 100文
查看详情点赞评论收藏浏览842023-06-13 16:21:43