go 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评论收藏浏览772023-06-14 09:58:31《千字文》全文,儿童启蒙必备。
《千字文》为南朝周兴嗣所编,它的撰作,相传还有一段故事;原来是当年梁武帝令殷铁石在王羲之书写的碑文中拓下不重复的一千个字,供皇子们学书用的。但由于字字孤立,互不联属,所以他又召来周兴嗣嘱道:“卿有才思,为我韵之。”周兴嗣只用了一个晚上就编好进呈武帝。这便是传至今日的《千字文》。周兴嗣的《千字文》精思巧构,知识丰瞻,音韵谐美,宜蒙童记诵,故成为千百年蒙学教科书。天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。寒来暑往,秋收冬藏。闰余成岁,律吕调阳。云腾致雨,露结为霜。金生丽水,玉出昆冈。剑号巨阙,珠称夜光。果珍李柰,菜重芥姜。海咸河淡,鳞潜羽翔。龙师火帝,鸟官人皇。始制文字,乃服衣裳。推位让国,有虞陶唐。吊民伐罪,周发殷汤。坐朝问道,垂拱平章。爱育黎首,臣伏戎羌。遐迩一体,率宾归王。鸣凤在竹,白驹食场。化被草木,赖及万方。盖此身发,四大五常。恭惟鞠养,岂敢毁伤。女慕贞洁,男效才良。知过必改,得能莫忘。罔谈彼短,靡恃己长。信使可覆,器欲难量。墨悲丝染,诗赞羔羊。景行维贤,克念作圣。德建名立,形端表正。空谷传声,虚堂习听。祸因恶积,福缘善庆。尺璧非宝,寸阴是竞。资父事君,曰严与敬。孝当竭力,忠则尽命。临深履薄,夙兴温凊。似兰斯馨,如松之盛。川流不息,渊澄取映。容止若思,言辞安定。笃初诚美,慎终宜令。荣业所基,籍甚无竟。学优登仕,摄职从政。存以甘棠,去而益咏。乐殊贵贱,礼别尊卑。上和下睦,夫唱妇随。外受傅训,入奉母仪。诸姑伯叔,犹子比儿。孔怀兄弟,同气连枝。交友投分,切磨箴规。仁慈隐恻,造次弗离。节义廉退,颠沛匪亏。性静情逸,心动神疲。守真志满,逐物意移。坚持雅操,好爵自縻。都邑华夏,东西二京。背邙面洛,浮渭据泾。宫殿盘郁,楼观飞惊。图写禽兽,画彩仙灵。丙舍旁启,甲帐对楹。肆筵设席,鼓瑟吹笙。升阶纳陛,弁转疑星。右通广内,左达承明。既集坟典,亦聚群英。杜稿钟隶,漆书壁经。府罗将相,路侠槐卿。户封八县,家给千兵。高冠陪辇,驱毂振缨。世禄侈富,车驾肥轻。策功茂实,勒碑刻铭。盘溪伊尹,佐时阿衡。奄宅曲阜,微旦孰营。桓公匡合,济弱扶倾。绮回汉惠,说感武丁。俊义密勿,多士实宁。晋楚更霸,赵魏困横。假途灭虢,践土会盟。何遵约法,韩弊烦刑。起翦颇牧,用军最精。宣威沙漠,驰誉丹青。九州禹迹,百郡秦并。岳宗泰岱,禅主云亭。雁门紫塞,鸡田赤诚。昆池碣石,钜野洞庭。旷远绵邈,岩岫杳冥。治本于农,务兹稼穑。俶载南亩,我艺黍稷。税熟贡新,劝赏黜陟。孟轲敦素,史鱼秉直。庶几中庸,劳谦谨敕。聆音察理,鉴貌辨色。贻厥嘉猷,勉其祗植。省躬讥诫,宠增抗极。殆辱近耻,林皋幸即。两疏见机,解组谁逼。索居闲处,沉默寂寥。求古寻论,散虑逍遥。欣奏累遣,戚谢欢招。渠荷的历,园莽抽条。枇杷晚翠,梧桐蚤凋。陈根委翳,落叶飘摇。游鹍独运,凌摩绛霄。耽读玩市,寓目囊箱。易輶攸畏,属耳垣墙。具膳餐饭,适口充肠。饱饫烹宰,饥厌糟糠。亲戚故旧,老少异粮。妾御绩纺,侍巾帷房。纨扇圆洁,银烛炜煌。昼眠夕寐,蓝笋象床。弦歌酒宴,接杯举殇。矫手顿足,悦豫且康。嫡后嗣续,祭祀烝尝。稽颡再拜,悚惧恐惶。笺牒简要,顾答审详。骸垢想浴,执热愿凉。驴骡犊特,骇跃超骧。诛斩贼盗,捕获叛亡。布射僚丸,嵇琴阮箫。恬笔伦纸,钧巧任钓。释纷利俗,并皆佳妙。毛施淑姿,工颦妍笑。年矢每催,曦晖朗曜。璇玑悬斡,晦魄环照。指薪修祜,永绥吉劭。矩步引领,俯仰廊庙。束带矜庄,徘徊瞻眺。孤陋寡闻,愚蒙等诮。谓语助者,焉哉乎也。
查看详情点赞评论收藏浏览922023-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文
查看详情点赞评论收藏浏览1002023-06-13 16:21:43go生成带logo的二维码!(补充)
代码:package main import ( "bytes" "encoding/base64" "fmt" "github.com/nfnt/resize" "image" _ "image/jpeg" "image/png" "github.com/skip2/go-qrcode" "golang.org/x/image/draw" "os" ) // CreateQrCodeBs64WithLogo 带logo的二维码图片生成 content-二维码内容 size-像素单位 logoPath-logo文件路径 func CreateQrCodeBs64WithLogo(content, logoPath, outPath string, size int) (data string, err error) { code, err := qrcode.New(content, qrcode.High) if err != nil { return } //code.DisableBorder = true //设置文件大小并创建画板 qrcodeImg := code.Image(size) outImg := image.NewRGBA(qrcodeImg.Bounds()) //读取logo文件 logoFile, err := os.Open(logoPath) if err != nil { return } logoImg, _, _ := image.Decode(logoFile) logoImg = resize.Resize(uint(size/10), 0, logoImg, resize.Lanczos3) // 添加边框 // 图片到边框距离 pic2FramePadding := logoImg.Bounds().Dx() / 10 // 新建一个边框图层 transparentImg := image.NewRGBA(image.Rect(0, 0, logoImg.Bounds().Dx()+pic2FramePadding, logoImg.Bounds().Dy()+pic2FramePadding)) // 图层颜色设为白色 draw.Draw(transparentImg, transparentImg.Bounds(), image.White, image.Point{}, draw.Over) // 将缩略图放到透明图层上 draw.Draw(transparentImg, image.Rect(pic2FramePadding/2, pic2FramePadding/2, transparentImg.Bounds().Dx(), transparentImg.Bounds().Dy()), logoImg, image.Point{}, draw.Over) //logo和二维码拼接 draw.Draw(outImg, outImg.Bounds(), qrcodeImg, image.Pt(0, 0), draw.Over) offset := image.Pt((outImg.Bounds().Max.X-transparentImg.Bounds().Max.X)/2, (outImg.Bounds().Max.Y-transparentImg.Bounds().Max.Y)/2) draw.Draw(outImg, outImg.Bounds().Add(offset), transparentImg, image.Pt(0, 0), draw.Over) buf := new(bytes.Buffer) _ = png.Encode(buf, outImg) // 写入文件 f, _ := os.Create(outPath) _ = png.Encode(f, outImg) res := base64.StdEncoding.EncodeToString(buf.Bytes()) return res, nil } func main() { s, err := CreateQrCodeBs64WithLogo("http://www.alingfeng.cn/", "logo.png", "qr.png", 512) if err != nil { fmt.Println(err) return } fmt.Println(s) } 结果:
查看详情点赞评论收藏浏览1102023-06-12 17:25:31Go 生成静态二维码和动态二维码
在我们生活和工作中,会遇到很多需要用到二维码的地方。二维码在很多场合使用,比如打开链接,扫码支付,扫码打开链接,扫码加好友等等。今天我们使用go来生成一下二维码试试,我们可以用这个库来生成。github.com/skip2/go-qrcode1、生成静态二维码比如我们经常用到的,扫码打开一个网页。package main import ( "image/color" "log" "github.com/skip2/go-qrcode" ) func main() { qr, err := qrcode.New("http://www.alingfeng.cn/", qrcode.Medium) if err != nil { log.Fatal(err) } else { qr.BackgroundColor = color.RGBA{255, 255, 255, 255} qr.ForegroundColor = color.Black qr.WriteFile(256, "./go_code.png") } }运行一下,就可以看到我们的二维码图片2、生成动态二维码也有很多时候我们会用到动态的二维码,如扫码支付,扫码打开链接,扫码加好友等,结合http 库,动态生成qrcode 并返回。而无需保存成图片。package main import ( "fmt" "log" "net/http" "time" "github.com/skip2/go-qrcode" ) func main() { http.HandleFunc("/qrcode", Qrcode) log.Fatal(http.ListenAndServe(":8008", nil)) } func Qrcode(w http.ResponseWriter, req *http.Request) { var err error defer func() { if err != nil { w.WriteHeader(500) return } }() q, err := qrcode.New(fmt.Sprintf("http://www.alingfeng.cn/?t=%d", time.Now().Unix()), qrcode.Medium) if err != nil { return } png, err := q.PNG(256) if err != nil { return } w.Header().Set("Content-Type", "image/png") w.Header().Set("Content-Length", fmt.Sprintf("%d", len(png))) w.Write(png) }然后我们访问地址就可以看到图片: 127.0.0.1:8008/qrcode,每刷新一下二维码会相应变化。
查看详情点赞2评论收藏1浏览752023-06-12 16:12:55MD5 与 SHA-256比较!示例(Go)
什么是MD5?MD5(Message-Digest Algorithm 5)是一种消息摘要算法,用于计算数据的哈希值。它可以将任意长度的数据转换为一个128位的哈希值,该哈希值可以用作数据的识别码。 MD5算法的计算过程非常简单:对数据进行哈希处理,生成一个128位的数字,该数字表示原始数据的特征值。由于MD5算法采用的是单向哈希函数,即只能从哈希值中计算出原始数据,而不能从原始数据中计算出哈希值,因此可以确保原始数据不被篡改。 虽然MD5算法被广泛使用,但其安全性一直受到质疑。SHA-256算法相比MD5算法更强,能够更好地保护数据的安全性。因此,在实际应用中,建议使用SHA-256等更强的算法来保护数据的安全性。什么是SHA-256?SHA-256(Secure Hash Algorithm 256)是一种哈希算法,常用于数字签名、文件完整性校验、数据加密等场景。它是一种消息认证码,用于确保数据完整性,可以有效地防止数据被篡改或者伪造。 SHA-256算法的输入是任意长度的二进制数据,输出是一个长度为32字节的哈希值。该哈希值可以用作数字签名的密钥,或者用于文件完整性校验。在数字签名中,使用SHA-256算法将数据和密钥一起计算,生成一个哈希值,该哈希值可以用于验证数据的完整性。在文件完整性校验中,将待校验的文件的前n个字节与一个哈希值进行比较,如果哈希值匹配,则说明文件未被篡改。 SHA-256算法的安全性得到了广泛认可,是目前最常用的哈希算法之一。不过需要注意的是,任何算法都不是绝对安全的,需要根据实际情况选择合适的算法和安全策略。示例(Go)md5生成:import ( "crypto/md5" ) // 计算哈希值 func hash(data string) (string, error) { h := md5.New() _, err := h.Write([]byte(data)) if err != nil { return "", err } return hex.EncodeToString(h.Sum(nil)), nil } // 使用示例 data := "hello world" result, err := hash(data) if err != nil { return } fmt.Println(result) // "b0baee9d279d34fa1dfd71aadb908c3f"SHA-256生成:import ( "crypto/sha256" ) // 计算哈希值 func hash(data string) (string, error) { h := sha256.New() _, err := h.Write([]byte(data)) if err != nil { return "", err } return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil } // 使用示例 data := "hello world" result, err := hash(data) if err != nil { return } fmt.Println(result) // "sha256:a3c25f34ed9f1dfcc4b4b41a8058d3438df8e224b3973ab0bb5408cddbc58ee3c2"
查看详情点赞评论收藏浏览1662023-06-12 15:28:13运营人必须掌握的6大类26个基本模型
5W2H分析法概念5W:Who、When、Where、What、Why2H:How、How MuchWHAT:是什么?目的是什么?做什么工作?WHY:为什么要做?可不可以不做?有没有替代方案?WHO:谁?由谁来做?WHEN:何时?什么时间做?什么时机最适宜?WHERE:何处?在哪里做?HOW :怎么做?如何提高效率?如何实施?方法是什么?HOW MUCH:多少?做到什么程度?数量如何?质量水平如何?费用产出如何?使用场景对场景和业务流程进行全面梳理,有助于完善用户故事的描述,弥补考虑问题时的疏漏STAR分析法概念按照4个维度,对任务或者场景状态去思考及总结。S:环境(Situation)T:目标(Task)A:行动(Action)R:成果(Result)使用场景对于场景和业务流程进行梳理,有助于需求调研收集、完善用户故事的描述,规划和明确产品的关键功能SMART分析法概念按照5个维度,对去任务或者项目进考核目标和考核标准的思考。S:具体项(Specific)M:可度量(Measurable)A:可实现(Attainable)R:关联情况(Relevant)T:时限(Time-based)使用场景明确任务的边界范围,确定产品功能的需求实现效果,参考制定工作任务项规划。SWOT分析法概念态势分析,就是将与研究对象密切相关的各种主要内部的优势(Strengths)、劣势(Weakness)和外部的机会(Opportunities)、威胁(Threats)等,依照矩阵形式排列列出,然后用系统地把各种因素相互匹配起来加以分析,从中得出一系列相应的结论。SO(优势-机会):利用起来,增长性战略WO(弱点-机会):需要改进,扭转型战略ST(优势-威胁):监视起来,多种经营战略WT(弱点-威胁):需要消除,防御型战略使用场景竞品分析,自身产品的战略规划,制定核心功能方向麦肯斯MECE分解法概念全称 Mutually Exclusive Collectively Exhaustive,中文意思“相互独立,完全穷尽”。各部分之间相互独立 (Mutually Exclusive):每项工作之间要独立,每项工作之间不要有交叉和重叠。所有部分完全穷尽 (Collectively Exhaustive):全部内容是全面、周密的、不遗漏的。使用场景对场景/用户/业务等分类拆解和梳理,分析事务的各项因素及核心因素WBS工作分解结构概念工作分解结构,全称Work Breakdown Structure,简称WBS。WBS的过程,是把一个项目按一定的原则进行分解,项目分解成一项项工作,直到分解不下去为止。如:项目→任务→工作→活动,分解好的一项项工作,可以再对应到“人、时间、资金投入”中。使用场景明确项目任务的边界范围,梳理工作事项,制定工作进度计划,确定阶段性的可交付成果SCQA模型概念SCQA模型是一个“结构化表达”工具,是麦肯锡咨询顾问芭芭拉·明托在《金字塔原理》中提出的。S(Situation)情景——由大家都熟悉的情景、事实引入。C(Complication)冲突——实际情况往往和我们的要求有冲突。Q(Question)疑问——怎么办?A(Answer)回答——我们的解决方案是……使用场景在任何场合的表达,开场白,开会发言,演讲报告,都可以通过SCQA模型快速组织内容。还适用于归纳总结,提升工作效率。DFEAS模型概念基于人的动物本能的“DFEAS”模型Demand需求Find找到Evaluation评估Action行动Share分享使用场景DFEAS营销模式加入了(Demand需求)和(Evaluation评估),锁定有需求的客户进行传播,加入品牌影响力和销售力,这使得企业可以在数十亿网民中选择精准的、有需求的客户进行有效传播和影响;让客户在购买时的各个产品和品牌的对比中,企业因为预先布局而获得优势;AIDMA模型概念AIDMA是消费者行为学领域很成熟的理论模型之一,AIDMA(S)模型。Attention注意Interest兴趣Desire欲望Memory记忆Action行动使用场景消费者如何从接触到信息到最后达成购买的一种逻辑。作为营销者,你可以按照模型去构建自己的获客模型,去检验自己的获客模型是否有效。AISAS模型概念AISAS模式的转变。在全新的营销法则中,两个具备网络特质的“s”——search(搜索),share(分享)的出现,指出了互联网时代下搜索(Search)和分享(Share)的重要性,而不是一味地向用户进行单向的理念灌输,充分体现了互联网对于人们生活方式和消费行为的影响与改变。Attention:引起注意Interest:引起兴趣Search:进行搜索Action:购买行动Share:人人分享使用场景AISAS 模型是目前最通用的“用户决策行为分析模型”,作为运营者就需要考虑如何引导用户的消费行为,形成人人分享的病毒传播效果。SIPS模型概念SIPS模型Sympathize 共鸣—— Identify 确认—— Participate 参与—— Share 分享使用场景“SIPS模型”则深刻展现了社交媒体时代消费者行为的新特点,打破了传统单向的消费模式,更加注重消费者与企业、消费者与消费者之间的双向互动,强调用户的意见和行为受到聚合特定人群的影响,从而产生独特的内在规律。大众媒体之前,消费者行为模式是DFEAS:需求-搜寻-评价-行动-分享;大众媒体时代,消费者行为模式是AIDMA(S):注意-兴趣-欲望-记忆-行动-分享;网络分众时代,消费者行为模式变为AISAS:注意-兴趣-搜索-行动-分享;移动互联时代,消费者行为模式又变为SIPS:共鸣-确认-参与-分享。用户体验5要素概念对产品设计进行5个层级的划分,从“抽象”逐步到“具体”:战略层:对应产品目标,用户需求。战略是对目标,需求的商业化方案的归纳。范围层:对应产品的信息和功能点,涉及到产品的侧重点和取舍。结构层:对应产品的实际落地,产品在这个层面开始具体化。框架层:对应产品具体内容的呈现,产品进一步具体化,落实到界面。表现层:对应产品的视觉传达和交互体验,是产品的美化。使用场景对工作计划进行阶段化梳理,产品的全流程过程的协作中都可参考马斯洛需求层次理论概念由美国心理学家马斯洛提出,认为人的需求由五个等级构成,从下到上分别是:生理需求安全需求归属与爱的需求尊重需求自我实现的需求使用场景对于用户需求、用户痛点的分析KANO模型概念通过分析“需求实现程度”与“用户满意度”的影响,将需求分为以下5种类型:兴奋型需求:让用户意想不到的好需求,实现了以后用户会赞不绝口。期望型需求:随着需求的完成,用户满意度也逐步变好。无差异型需求:做出来后,用户满意度也不会变好。基本型需求:必备,理所应当。反向型需求:做出来后,用户满意度反而变糟。使用场景需求调研和需求分析,需求分类、需求优先级迭代规划,产品上线后的反馈验证参照工作流程优先级排序概念以“轻重缓急”的四象限法来确定需求优先级。马上做:如果你总是有紧急又重要的事情要做,说明你在时间管理上存在问题,设法减少它。计划做:尽可能地把时间花在重要但不紧急(第二象限)的事情上,这样才能减少第一象限的工作量。授权做:对于紧急但不重要的事情的处理原则是授权,让别人去做。减少做:不重要也不紧急的事情尽量少做。使用场景新产品需求的规划排期,功能开发和缺陷解决的优先级排序,确立产品下一次迭代优化的重点和方向,日常工作的排期和处理先后顺序PDCA循环概念PDCA循环的含义是将质量管理分为四个阶段,即:P:计划 (Plan) 包括方针和目标的确定,以及活动规划的制定。D:执行 (Do) 根据已知信息,设计具体的行动方案;再根据方案,执行具体行动。C:检查 (Check) 总结结果,明确效果,找出问题。A:处理 (Act) 对检查的结果和问题进行具体处理,没有解决的问题进入下一个PDCA循环。使用场景敏捷项目Scrum模式或MVP产品的规划、设计、开发,对于需求缺陷的跟踪流程,需求的优化和迭代AARRR模型概念用户增长的5个指标,分别是:A:获取(Acquisition)A:激活(Activation)R:留存(Retention)R:收入(Revenue)R:传播(Referral)使用场景理解获客和维护客户的原理,根据跳转情况验证用户体验细节,根据漏斗模型判断流失情况。RFM模型概念基于三个维度,分析客户消费行为特征。R:最近一次消费 (Recency)F:消费频率 (Frequency)M:消费金额 (Monetary)简单地根据三个维度高低划分进行的客户分类:重要价值客户:R近、F频次和M金额都很高,超级的忠实客户,重点维护的VIP。重要保持客户:R远、F频次和M金额都很高,说明这是个一段时间没来的忠诚客户。重要发展客户:R近、M金额很高,但F频次不高,忠诚度不高,是潜力用户。重要挽留客户:R远、F频次不高,但M金额高,是将要流失或者已经要流失的用户。事实上,维度的指标可以更细,就能得到更细分的用户分类。使用场景根据不同维度的多级指标对客户进行更细分的分类完善用户画像或用户标签用户金字塔模型概念运营工作时需要抓住的是金字塔顶端20%的用户;可以利用用户进行有效地管理用户;并且每个模块可以再进行拆解成小金字塔,作为管理工具,增加用户和用户之间的关系。使用场景产品拓新的时候,从KOL到KOC,进而逐渐到普通用户,如此这般可以更快速的获得产品启动。而且还可以对金字塔模型进行拆解,建立圈层文化。用户增长s型,J型曲线概念优秀产品的生命周期好比一条S形曲线:首先是初期阶段,产品的市场渗透率增长比较缓慢。随后,渗透率将进入一个从缓慢到快速的爬坡过程,也就是增长期。对于较差的产品来说,这个曲线不会趋于平稳,最终会走向零点。与之相反,优秀产品的曲线会有上升的过程,最后趋于平稳。使用场景根据实际情况选择有意义的指标和时间段,通过增加产品线,扩大总目标市场,开拓新市场,保证各个产品的增长曲线相互叠加,从而保证整体的持续增长。生命周期概念生命周期(Life Cycle)的概念应用很广泛,特别是在政治、经济、环境、技术、社会等诸多领域经常出现,其基本涵义可以通俗地理解为“从摇篮到坟墓”(Cradle-to-Grave)的整个过程。对于某个产品而言,就是从自然中来回到自然中去的全过程,也就是既包括制造产品所需要的原材料的采集、加工等生产过程,也包括产品贮存、运输等流通过程,还包括产品的使用过程以及产品报废或处置等废弃回到自然过程,这个过程构成了一个完整的产品的生命周期。使用场景不管是用户还是产品,都是有生命周期的说法,作为运营人员,需要根据用户/产品的不同阶段,指定不同的运营策略。90-9-1法则概念“90-9-1”规则是内容社区的一个知名理论,指的是在内容社区中 90%的用户只是浏览,9%的用户会参与讨论,只有 1%的用户会积极的创造内容。当然具体的数值多少不重要,核心是“参与度的极大不均衡”。使用场景虽然90-9-1法则在某些特定的社区已经被不复存在,但是我们依然可以通过这个法则去挖掘更优质是内容创造者。通过顶部流量用户引导底部90%的用户参与到内容创作中来北极星指标概念北极星指标又叫唯一重要指标,就是把商业闭环设计的核心价值主张,作为用户增长的第一关键指标,为公司发展提供了选择正确的方向。使用场景新的增长模式是数据驱动的增长模式,是精益地、敏捷地进行“构建-衡量-学习”循环,即通过对数据的分析提出假设,通过实验验证假设,衡量实验得到的数据,重复这一循环来找到增长点。LTV概念LTV(CLV):用户的终身价值LTV的相对准确的计算公式是:(某个客户每个月的购买频次*每次的客单价*毛利率)*(1/月流失率)。其中的LT(生命周期)=1/月流失率是得出平均每个客户在该平台能够留存的总时长是多少月。使用场景结合上面的用户生命周期来看,运营人员就是需要通过各种运营策略提高用户留存,尽一切可能延长用户的生命周期,并且在生命周期中尽一切可能产生商业价值。CAC概念CAC:用户获取成本CAC 是 Customer Acquisition Cost 的缩写,意思是“用户获取成本”。使用场景判断不同渠道下用户的获取成本,通过综合计算和优化投放策略,降低用户获取成本。小结:增量期:CAC低,LTV低。如果一款产品单独切入用户需求开辟蓝海市场,又恰好用户的需求确实没有满足,市场仍旧存在真空。那么早期用户的CAC也不会太高。这时候还是要关注产品的迭代和用户增长。成长期:CAC高,LTV低。某模式或领域证明其有可行性,或者单纯的资本热,就会吸引其他玩家入场,竞争对手出现,瓜分蛋糕。导致CAC的升高。用户增长的作用还是很重要,同时要做好市场和竞品分析,在竞争中保持自己的优势。成熟期:CAC高,LTV高。产品和用户产生黏性。例如社交产品的关系链,电商产品的会员,以及用户积分和等级体系等,都会让用户手机常驻几款APP。用户能开始展现商业价值,故称为成熟期。这时候需要关注的是商业化和变现,提高用户的价值。衰退期:CAC高,CLV低。市场已经饱和,没有持续的新用户为产品输血。这时候更应该关注用户的留存,延长产品的生命,同时关注新机遇。PBP概念PBP的意思是花出去的用户获取成本可以在多长时间内回本。如果忽略PBP(回收期),哪怕LTV>CAC公司也可能会出问题。一般市场上认为PBP在一年以内为佳,因为LTV的计算是可以长达5-10年的,但现金流和融资压力却是逐年累积的,PBP越短,越有利于公司的现金流和再投入,也能减轻公司的融资压力等。使用场景PBP就是加入了时间限制——多少时间内,LTV大于CAC。PBP太长,就要和用户流失和市场周期做抗争了。后记:当然,在实际工作中,还有很多相关的模型,比如GMV计算模式,转化率漏斗,ARPU值模型,PLC模型,Heart模型等等。这些都是需要我们在运营过程中不断学习的。参考链接:https://www.zhihu.com/question/423613286/answer/2334398764?utm_psn=1649690718703792128
查看详情点赞2评论收藏1浏览822023-06-07 10:14:17Go 实现WebSocket,初步实操
什么是长连接和短连接?在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:Connection:keep-alive在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。Go WebSocket今天我们会用Go语言使用WebSocket,经过多方收集资料,整理了后端的服务端+客户端,然后服务端和前端的链接两个示例,下面是代码,供大家研究。今天我们用的是Gin框架实现一个长链接。1、服务端+客户端(后端)服务端:package main import ( "fmt" "log" "net/http" "time" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{} func main() { // 使用gin框架,和普通的http协议的服务器没什么不一样 s := gin.Default() s.GET("/sendMsg", echo) _ = s.Run("127.0.0.1:8090") } func echo(c *gin.Context) { //服务升级,对于来到的http连接进行服务升级,升级到ws cn, err := upgrader.Upgrade(c.Writer, c.Request, nil) defer cn.Close() if err != nil { panic(err) } for { mt, message, err := cn.ReadMessage() fmt.Println("接受到消息", message) if err != nil { log.Println("server read:", err) break } log.Printf("server recv msg: %s", message) msg := string(message) fmt.Println(msg, "msg") if msg == "clent" { message = []byte("客户端来了") } err = cn.WriteMessage(mt, message) if err != nil { log.Println(" server write err:", err) break } } } 客户端:package main import ( "log" "net/url" "os" "os/signal" "time" "github.com/gorilla/websocket" ) func main() { interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) u := url.URL{Scheme: "ws", Host: "127.0.0.1:8090", Path: "/sendMsg"} log.Printf("client1 connecting to %s", u.String()) c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { log.Fatal("dial server:", err) } defer c.Close() done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("client read err:", err) return } log.Printf("client recv msg: %s", message) } }() for { select { // if the goroutine is done , all are out case <-done: return case <-time.Tick(time.Second * 5): err := c.WriteMessage(websocket.TextMessage, []byte("clent")) if err != nil { log.Println("client write:", err) return } case <-interrupt: log.Println("client interrupt") err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Println("client1 write close:", err) return } select { case <-done: case <-time.After(time.Second): } return } } } 分别启动服务端和客户端:服务端会根据客户端发来的消息回复2、服务端+前端(前后端)接下来,我们用前后端交互一下websocket前端页面:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>websocket测试</title> <script src="http://www.alingfeng.cn/js/jquery.min.js"></script> </head> <body> <button id="clickButton">点击测试websocket</button> <script> $("#clickButton").click(function () { var name = $("#name").val(); initWebpack(name); }); </script> <script> var planWebsocket = null; var planIP = "127.0.0.1"; // IP地址 var planPort = "8090"; // 端口号 function initWebpack(clickName) { //初始化websocket if ("WebSocket" in window) { planWebsocket = new WebSocket( "ws://" + planIP + ":" + planPort + "/sendMsg" ); // 通信地址 setInterval( (planWebsocket.onopen = function (event) { console.log("建立连接"); let sendData = { command: "sendMsg", data: [{ msg: "服务端,我发送了消息,注意查收!" }], }; planWebsocket.send(JSON.stringify(sendData)); // 发送获取数据的接口 }), 2000 ); planWebsocket.onmessage = function (event) { // console.log('收到消息:' + event.data) let data = JSON.parse(event.data); if (data.command == "sendMsg") { var planData = data.data; //返回的数据 console.log(planData); } else if (data.command == "getscenes") { // 其他命令 } }; planWebsocket.onclose = function (event) { console.log("连接关闭"); }; planWebsocket.onerror = function () { alert("websocket通信发生错误!"); }; } else { alert("该浏览器不支持websocket!"); } } // initWebpack(); //调用 </script> </body> </html> 服务:package main import ( "fmt" "log" "net/http" "time" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) // var upgrader = websocket.Upgrader{} var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, // 解决跨域问题 CheckOrigin: func(r *http.Request) bool { return true }, } func main() { // 使用gin框架,和普通的http协议的服务器没什么不一样 s := gin.Default() s.GET("/sendMsg", echo) _ = s.Run("127.0.0.1:8090") } func echo(c *gin.Context) { //服务升级,对于来到的http连接进行服务升级,升级到ws cn, err := upgrader.Upgrade(c.Writer, c.Request, nil) defer cn.Close() if err != nil { panic(err) } for { mt, message, err := cn.ReadMessage() fmt.Println("接受到消息", message) if err != nil { log.Println("server read:", err) break } log.Printf("server recv msg: %s", message) msg := string(message) fmt.Println(msg, "msg") // if msg == "clent1" { // message = []byte("客户端1来了") // } else if msg == "clent2" { // message = []byte("你好客户端2") // } message = []byte("客户端,我已接收") for i := 0; i < 100; i++ { time.Sleep(1000000000) err = cn.WriteMessage(mt, message) } if err != nil { log.Println(" server write err:", err) break } } } 测试:我们初步了解Go语言做websocket就可以了。
查看详情点赞8评论收藏1浏览1312023-06-03 10:04:00文心一言市场负责人怒怼科大讯飞
针对科大讯飞因AI小作文股价大跌一事,百度文心一言市场负责人张文全在朋友圈怒怼,称“听闻有友商把自己股价大跌,归咎于有人利用文心一言写了篇命题小作文,也是醉了。先别说小作文这事真假 (目前看来只怕是策划痕迹太重),如果AI作文有这本事,百度员工自己先炒一下自己股价不香吗?中国发展自己的大模型技术挺不容易的把精力放到正事上吧,还请友商解决好自己的问题,别动不动就碰瓷别人,大家的眼睛都雪亮的。”科大讯飞股价24日午后意外大幅下跌,午后开盘下跌8.82%至53.88元/股。对此,科大讯飞回应表示,“股价下跌系某生成式AI写作虚假小作文导致,谣传风险为不实消息。”据悉,有人利用文心一言写做了一篇“科大讯飞出现重大风险的警示文”,该消息流出后引发广泛关注。
查看详情点赞1评论收藏浏览892023-05-26 15:27:54我有一个想法,开一个常用的热门工具版块,欢迎大家推荐和留言!!!
点赞3评论7收藏2浏览2192023-05-25 14:11:31