All Posts

go标准库——ioutil.ReadAll的实现

序 最近准备学习一下golang的标准库,详细的阅读部分源码,这个目录记录一下学习的过程和心得 go语言的ioutil包提供了很多方便的io操作的工具集,本文主要详细分析ReadAll方法的源码实现。 ReadAll是很常用的一个方法,用来一次性的读取io.Reader当中的数据。 源码实现 1. ReadAll 阅读下方的源码我们可以发现,ReadAll其实调用了一个非导出的方法,我们一步一步的追踪 // ReadAll reads from r until an error or EOF and returns the data it read. // A successful call returns err == nil, not err == EOF. Because ReadAll is // defined to read from src until EOF, it does not treat an EOF from Read // as an error to be reported. // ReadAll从r读取数据直到EOF或遇到error,返回读取的数据和遇到的错误。 // 成功的调用返回的err为nil而非EOF。 // 因为本函数定义为读取r直到EOF,它不会将读取返回的EOF视为应报告的错误。 func ReadAll(r io.

使用chromedp解决反爬虫问题

前言 最近We川大上的教务处公告新闻已经很久没有更新了,想到可能是ip被封了,查了一下log,发现并不是,而是获取到的页面全变成了混淆过的js,下面放两个格式化的函数 function _$Es(_$Cu) { _$Cu[14] = _$v9(); _$Cu[_$yf(_$ox(), 16)] = _$Dn(); var _$cR = _$CR(); _$cR = _$iT(); return _$DA(); } function _$Dk(_$Cu) { var _$x5 = _$Dv(); var _$x5 = _$EB(); if (_$Ex()) { _$w9 = _$Dw(); } _$Cu[_$yf(_$EJ(), 16)] = _$ED(); _$Cu[_$yf(_$Ep(), 16)] = _$EP(); _$w9 = _$EB(); return _$Cu[_$yf(_$v9(), 16)]; } function _$rK() { var _$aJ = _$c0(_$DN()); _$aJ = _$BC(_$aJ, 2); var _$Ce = _$yr(_$qt()); for (var _$Cu = 0; _$Cu < _$aJ[_$gX()]; _$Cu++) { _$aJ[_$Cu] = _$Ce + _$aJ[_$Cu]; } return _$aJ; } 看着这一堆就头大,但是本着只要是浏览器能够渲染出来的页面爬虫就可以爬到的原则,一步一步的解决

We川大开发笔记@0.2.0

序 可以搜索小程序we川大直接体验 这不是刚刚发完0.1.0的笔记么?怎么0.2.0都出来了? 没有看错,效率就是那么高,上一篇也提到了0.1.0审核通过的时候0.2.0就基本已经完成了,而且现在已经上线了(准确的说是0.2.1版本),这一次的审核快了许多,只用了不到两天就已经审核通过了 功能预览 这一版主要新增三个功能,然后就是一些优化: 1.反馈 参考we重邮,直接和github的issue关联,所有提交的反馈信息,都会新建一条issue,为了防止滥用,每天的反馈次数做了一定的限制 这个后端上直接采用了Google的go-github包,开发起来十分的方便,只是文档资料不是特别的丰富,之后会专门总结一下 2.空闲教室查询 学校的空闲教室查询页面:http://cir.scu.edu.cn/cir/index.html 这是学校难得做的比较友好的站点,对于这个需要后端做一次接口中转即可 3.新闻Tag列表 这一版可以直接通过点击列表的tag,查看前20条包含该tag的新闻, 至于为什么是20条,因为一个很奇怪的bug现在还没有解决。 两个页面,A,B包含了同一个模块C,在模块C当中可以点击跳转到B,现在的问题就是在A页面的C模块当中点击跳转到B页面之后,B页面的C模块的scroll-view绑定的所有事件都会消失 图片预览 博客原文&&开源地址 https://github.com/mohuishou/scuplus-wechat http://lailin.xyz/post/We川大开发笔记@0.2.0/ 可以关注开发进度或者提交反馈或者是PR,star多多益善

We川大开发笔记@0.1.0

序 微信小程序已经出来一年左右了,然后之前也写过一个scuplus的web项目,但是还没有正式上线就无疾而终了,当然也不是一点用处都没有,拆分出来了两个小的功能模块,一个是绩点计算器,一个快捷评教,绩点计算器的日PV快要破3W了,UV已经破1W了,大家期末看成绩的心情依旧是那么的急迫。 按理来说,我即将毕业做这些其实不太好,毕业之后代码的维护以及运营都是一个大问题,但是川大一直缺少一个综合型的APP或者网站,学校官方的网站做的都及其的不友好,而且十分的分散,所以一直有这个想法,想做一个集新闻资讯、比赛资讯/找队友/拉票,教务查询,课程推荐/排名/评价/选课,书籍查询/借阅于一体的一个综合型网站。当然这个想法涉及到的东西有点多,吸取之前的教训,这次打算一步一步的来,前期做功能,后期做优化,分模块上线 使用微信小程序开发好处是不用考虑浏览器的兼容性也不用考虑去做两个APP,以及各种型号的手机,但是不好的地方就是所有的界面都只能靠自己去实现,基本没有现成的ui框架,有时候写的有点蛋疼(PS我是一个后端)。然后就是审核,微信的审核0.1.0版本用了5天才完成,这个时间我的0.2.0版本已经基本开发完成了 项目已经开源,可以关注开发进度或者提交反馈或者是PR,star多多益善 https://github.com/mohuishou/scuplus-wechat 扫码体验 功能预览 0.1.0 版本只是完成了基本的框架,以及相对来说比较常用的功能: 最新资讯(青春川大/scuinfo/教务处/学工部等) 成绩/GPA查询 课表查询 图片预览

招银网络面试总结

三面同时进行,每一面间隔不超过五分钟,前面两面技术面最后一面HR,完全不会JAVA,结果一直问JAVA心态爆炸 一面(20min) 1. 自我介绍 2. JAVA用过么?准备去什么地方? 用过一天写了一个小APP 3. JAVA的HashMap怎么实现?PUT一次做了什么操作 不会 4. JAVA的GC怎么实现 不会,强行说了一波PHP的GC 5. Mysql的锁 Innodb支持到行级锁,MyISAM只支持到表 6. 求一个二叉树任意两节点的距离,时间复杂度是多少? 7. 设计模式了解不?装饰器模式解释一下,写一个 解释了一下,没有写,后面让写了一个工厂 > 还有一些忘了 二面(15min) 1. 自我介绍 2. JAVA的GC怎么实现。。。又来了 3. Mysql去除重复项 4. Mysql触发器机制 5. 设计一个无限极分类的数据库表 6. 怎么把去处来的数据树型结构化 三面(35min) 1. 拿了一波简历,成绩单,自我介绍 2. 为什么不想留在成都 3. 成绩单上很多60分,飘过还是重修 飘过 4. 现在面试了哪些公司,有没有收到offer意向 5. 简单的介绍了一个项目 6. 介绍了社团研发部部长和学院团副经历 还有一些记不住了

大疆面试总结

感谢大疆的第一份Offer 一面(1h 40min) 两个面试官问了不同方向的问题 0. 自我介绍 1. 详细的介绍了两个项目 2. 一道算法题 求n!末尾有多少个0 面试官很好,引导着做的 3. 进程、线程、协程对比 4. 协程为什么可以有成千上万个,线程呢 5. Ruby什么时候学的,从开始接触到写项目之间用了多久 实习的时候初学,用了3天 6. Golang 切片如何删除数据 7. Golang 的结构体的组合 8. Golang interface的设计 9. Mysql的两种引擎的对比 10. 可不可以提前实习 11. 愿不愿意去他的部门 还有很多问题忘记了 二面 (1h 20min) 0. 自我介绍 1. 详细的介绍了1个项目 2. 进程、线程、协程对比 3. PHP数组在内核当中如何实现 4. PHP和Golang的区别 5. 能不能提前实习 还有很多问题忘记了

归并排序

说明 归并排序:是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用 步骤 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 设定两个指针,最初位置分别为两个已经排序序列的起始位置 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 重复步骤3直到某一指针达到序列尾 将另一序列剩下的所有元素直接复制到合并序列尾 效果 示例 package merge //INFINITY 一个比较大的值用作哨兵 const INFINITY = 0xffff func merge(arr []int, start, end int) { if start < end { //从中间划分,分别左右两边排序 mid := (end + start) / 2 merge(arr, start, mid) merge(arr, mid+1, end) //下面进行归并操作,将两个长度较小但是已经排序完成的数组合并成一个较长长度的排序数组 //新建一个数组用于存放左边的值 arr1 := make([]int, mid-start+2) copy(arr1, arr[start:mid+1]) arr1[mid-start+1] = INFINITY //新建一个数组用于存放右边的值 arr2 := make([]int, end-mid+1) copy(arr2, arr[mid+1:end+1]) arr2[end-mid] = INFINITY //比较大小 j, k := 0, 0 for i := start; i <= end; i++ { if arr1[j] <= arr2[k] { arr[i] = arr1[j] j++ } else { arr[i] = arr2[k] k++ } } } }

堆排序

说明 堆积排序: 是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 步骤 建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点,此处len是堆中元素的个数。建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程,相当于o(h1)+o(h2)…+o(hlen/2) 其中h表示节点的深度,len/2表示节点的个数,这是一个求和的过程,结果是线性的O(n)。 调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,如果最大(小)值不是节点i而是它的一个孩子节点,那边交互节点i和该节点,然后再调用调整堆过程,这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,因为是沿着深度方向进行调整的。 堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。堆排序过程的时间复杂度是O(nlgn)。因为建堆的时间复杂度是O(n)(调用一次);调整堆的时间复杂度是lgn,调用了n-1次,所以堆排序的时间复杂度是O(nlgn)[2] 注意: 根节点在数组当中存放的位置是0,所以第i个节点的左孩子是2i+1,右孩子是2i+2 示例 实现 package HeapSort import ( "fmt" ) //HeapSort 堆排序 func HeapSort(arr []int) { LEN := len(arr) for i := LEN/2 - 1; i >= 0; i-- { HeapAjust(arr, i, LEN) } for i := LEN - 1; i > 0; i-- { arr[i], arr[0] = arr[0], arr[i] HeapAjust(arr, 0, i) } } //HeapAjust 堆调整 func HeapAjust(arr []int, start int, length int) { tmp := arr[start] for i := 2*start + 1; i < length; i = i * 2 { if i+1 < length && arr[i] < arr[i+1] { i++ } if tmp > arr[i] { break } arr[start] = arr[i] start = i } arr[start] = tmp }

冒泡排序

冒泡排序 定义 冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。 步骤: 比较相邻的元素(从后往前)。如果第一个比第二个大,就交换他们两个。 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 (如果这一步没有出现任何一次交换,那么说明所有的元素已经有序,不需要再进行下面的步骤了) 针对所有的元素重复以上的步骤,除了最后一个。 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 图片示例 程序示例(go) func SortInt(a []int) ([]int, int) { //交换次数,计数 n := 0 aLen := len(a) for i := aLen - 1; i >= 0; i-- { //标记,如果flag一次冒泡之后没有改变,那么证明排序已完成,不需要再次排序,直接退出 flag := 0 //一次冒泡 for j := 0; j < i; j++ { if a[j] > a[j+1] { //交换两个变量的值,无需引入临时变量 a[j], a[j+1] = a[j+1], a[j] n++ //有交换,flag=1 flag = 1 } } //判断一次冒泡,是否存在交换 if flag == 0 { break } } return a, n }

shell排序

Shell排序 说明 希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。 步骤 设置间隔(传统间隔为N/2) 插入排序 图片示例 程序示例 传统实现 //SortInt 传统shell排序,间隔为N/2 //相邻间隔可能不互质,可能会出现前置排序无用的情况 func SortInt(a []int) ([]int, int) { n := 0 aLen := len(a) //定义间隔 for i := aLen / 2; i > 0; i = i / 2 { //插入排序 for j := i; j < aLen; j++ { tmp := a[j] k := j for ; k >= i && tmp < a[k-i]; k = k - i { a[k] = a[k-i] n++ } a[k] = tmp } } return a, n } Hibbard算法 //SortHibbardInt Hibbard算法,间隔为2^k-1 func SortHibbardInt(a []int) ([]int, int) { n, i := 0, 0 aLen := len(a) for i = 1; i <= aLen-1; i = i*2 + 1 { } //定义间隔 for ; i > 0; i = (i - 1) / 2 { // println(i) //插入排序 for j := i; j < aLen; j++ { tmp := a[j] k := j for ; k >= i && tmp < a[k-i]; k = k - i { a[k] = a[k-i] n++ } a[k] = tmp } } return a, n }