一、排序算法之go实现
1.冒泡排序
func bubbleSort(slice []int){
for i := 0; i < len(slice); i++{
ctn := 0
for j := 0; j < len(slice) - i - 1; j++{
if slice[j] > slice[j+1]{
slice[j], slice[j+1] = slice[j+1], slice[j]
ctn ++
}
}
if ctn == 0{
break
}
}
}
func main(){
slice := []int{2,6,4,3,1,7,9,12,31,15}
bubbleSort(slice)
fmt.Println(slice)
}
View Code
2.选择排序
func selectSort(slice []int){
var min_ind int
for i := 0; i < len(slice); i++{
min_ind = i
for j := i + 1; j < len(slice); j++{
if slice[j] < slice[min_ind]{
slice[j], slice[min_ind] = slice[min_ind], slice[j]
}
}
}
}
func main(){
slice := []int{2,6,4,3,1,7,9,12,31,15}
selectSort(slice)
fmt.Println(slice)
}
View Code
3.插入排序
func insertSort(slice []int){
for i := 1; i < len(slice); i++{
for j := i; j > 0; j--{
if slice[j] > slice[j - 1]{
break
}
slice[j], slice[j - 1] = slice[j - 1], slice[j]
}
}
}
func main(){
slice := []int{2,6,4,3,1,7,9,12,31,15}
insertSort(slice)
fmt.Println(slice)
}
View Code
4.快速排序
func quickSort(slice []int, first int, last int){
if first >= last{
return
}
mid_val := slice[first]
low := first
high := last
for low < high{
for (low < high && slice[high] >= mid_val){
high--
}
slice[low] = slice[high]
for (low < high && slice[low] <= mid_val){
low++
}
slice[high] = slice[low]
}
slice[low] = mid_val
quickSort(slice, first, low - 1)
quickSort(slice, high + 1, last)
}
func main(){
slice := []int{2,6,4,3,1,7,9,12,31,15}
quickSort(slice, 0, len(slice) - 1)
fmt.Println(slice)
}
View Code
二、go中的struct
1.用来自定义复杂数据结构
2.struct里面可以包含多个字段(属性)
3.struct类型可以定义方法(注意和函数的区分)
4.struct类型是值类型
5.struct类型可以嵌套
6.go语言没有calss类型,只有struct类型
struct的定义
1.struct声明
type 标识符 struct{
field1 type
field2 type
}
2.struct中字段访问,和其它语言一样,使用点
3.struct定义的三种形式
var stu Student
var stu *Student = new(Student)
var stu *Student = &Student{}
//其中b和c返回的都是指向结构体的指针,访问形式如下:
(*stu).Name,可以简写成stu.Name
4.struct的内存布局:struct中的所有字段在内存中是连续的,布局如下:
type Student struct{
Name string
Age int
}
func main(){
var stu1 = Student{
Name: "bob",
Age: 18,
}
var stu2 Student
stu2.Name = "tony"
stu2.Age = 18
fmt.Println(stu1)
fmt.Println(stu2)
fmt.Println(stu1.Name)
fmt.Printf("addr:%p\n",&stu1.Name)
fmt.Printf("addr:%p\n",&stu1.Age)
}
View Code
链表定义
每个节点包含下一个节点的地址,通常把链表中的第一个节点叫做链表头
type Student struct{
Name string
Next *Student
}
type Student struct{
Name string
Age int
Next *Student
}
func trans(p *Student){
for p != nil{
fmt.Println(*p)
p = p.Next
}
}
func main(){
head := Student{
Name: "b1",
Age: 18,
}
stu1 := Student{
Name: "b2",
Age: 32,
}
head.Next = &stu1
trans(&head)
}
链表实现
package main
import "fmt"
type Student struct{
Name string
Age int
Next *Student
}
func forAppend(p *Student, n int){
tail := p
for i := 0; i < n; i++{
stu := Student{
Name: fmt.Sprintf("b%d",i),
Age: 19 + i,
}
tail.Next = &stu
tail = &stu
}
}
func trans(p *Student){
for p != nil{
fmt.Println(*p)
p = p.Next
}
}
func main(){
head := Student{
Name: "b",
Age: 18,
}
forAppend(&head,10)
trans(&head)
}
循环后插
package main
import "fmt"
type Student struct{
Name string
Age int
Next *Student
}
func forInsert2(p *Student, n int) *Student{
for i := 0; i < n; i++{
stu := Student{
Name: fmt.Sprintf("b%d",i),
Age: 19 + i,
}
stu.Next = p
p = &stu
//只是更改了指针的副本
}
return p
}
func trans(p *Student){
for p != nil{
fmt.Println(*p)
p = p.Next
}
}
func main(){
head := Student{
Name: "b",
Age: 18,
}
p := forInsert2(&head, 10)
trans(p)
}
循环头插1
package main
import "fmt"
type Student struct{
Name string
Age int
Next *Student
}
func forInsert1(p **Student, n int){
//传入指针的地址
for i := 0; i < n; i++{
stu := Student{
Name: fmt.Sprintf("b%d",i),
Age: 19 + i,
}
//更改指针的地址
stu.Next = *p
*p = &stu
}
}
func trans(p *Student){
for p != nil{
fmt.Println(*p)
p = p.Next
}
}
func main(){
// head := Student{
// Name: "b",
// Age: 18,
// }
// p := forInsert2(&head, 10)
// trans(p)
var head *Student = new(Student)
head.Name = "b"
head.Age = 18
forInsert1(&head, 10)
trans(head)
}
循环头插2
//删除属性Name为b8的节点
func del(p *Student, name string){
prev := p
for p != nil{
if p.Name == name{
prev.Next = p.Next
}
prev = p
p = p.Next
}
}
//无法删除头节点
//改写
func del(p **Student, name string){
//前一个节点
var prev *Student
//当前节点
cur := *p
for cur != nil{
if cur.Name == name{
//如果是删除头节点,就更改头节点的地址
if cur == *p{
*p = (*p).Next
}else{
prev.Next = cur.Next
}
break
}
prev = cur
cur = cur.Next
}
}
func main(){
var head *Student = new(Student)
head.Name = "b"
head.Age = 18
forInsert1(&head, 10)
del(&head, "b8")
trans(head)
}
删除指定节点
双链表的定义
两个指针分别指向前一个节点和后一个节点
type Student struct{
Name string
Next *Student
}
二叉树定义:
两个指针分别指向左子树和右子树
type Student struct{
Name string
Left *Student
Right *Student
}
//二叉树
package main
import "fmt"
type Student struct{
Name string
Age int
Left *Student
Right *Student
}
func trans(root *Student){
if root == nil{
return
}
fmt.Println(root.Name)
trans(root.Left)
trans(root.Right)
}
func main(){
var root = new(Student)
root.Name = "stu0"
root.Age = 18
var left01 = new(Student)
left01.Name = "stu1"
left01.Age = 20
var right01 = new(Student)
right01.Name = "stud2"
right01.Age = 25
var right02 = new(Student)
right02.Name = "stud3"
right02.Age = 30
root.Left = left01
root.Right = right01
right01.Left = right02
trans(root)
}
View Code
5.结构体是用户单独定义的类型
type integer int
var i integer = 1
var j int = 2
//i,j是属于不同类型
package main
import "fmt"
type myInt int
func main(){
var a myInt = 10
var b int = 20
//编译不通过,a和b是不同的类型
a = b
fmt.Println(a)
}
func main(){
var a myInt = 10
var b int = 20
//需要强制转换
a = myInt(b)
fmt.Println(a)
}
View Code
golang没有构造函数,可以使用工厂模式解决这个问题
package model
type Student struct{
Name string
Age int
}
func NewStudent(name string, age int)*student{
return &student{
Name: name
Age: age
}
}
packeage main
//s := new(Student)
s := model.NewStudent("tony",20)
View Code
6.struct中的tag
我们可以为struct中的每个字段,写上一个tag,这个tag可以通过反射的机制获取到,最常用的场景就是json的序列化与反序列化
type Student struct{
Name string "this is name field"
Age int "this is age field"
}
package main
import (
"fmt"
"encoding/json"
)
type Student struct{
Name string `json:"name"`
Age int `json:"age"`
}
func main(){
stu := Student{
Name: "bob",
Age: 18,
}
data, err := json.Marshal(stu)
if err != nil{
fmt.Println("json encode faile")
return
}
fmt.Println(string(data))
}
View Code
7.结构体中字段可以没有名字,即匿名字段
type Train struct{
Car
Start time.Time
int
}
package main
import "fmt"
type Student struct{
Name string
Age int
}
type Class struct{
Name string
Student
}
func main(){
var c1 Class
//当结构体中有该字段,直接访问
c1.Name = "T1"
//通过类型点的方式访问匿名字段
c1.Student.Name = "bob"
c1.Student.Age = 18
//不能同时出现相同类型的两个匿名字段
fmt.Println(c1)
}
View Code
方法
golang中的方法是作用在特定类型的变量上,因此自定义类型都可以有方法,不仅仅是struct
1.定义
func(recevier type) methodName(参数列表)(返回值列表){
}
type Student struct{
Name string
Age int
}
//this就是stu,init为方法名
func (this *Student) init(name string, age int){
this.Name = name
this.Age = age
}
func main(){
var stu Student
}
View Code
2.方法的调用
func (this *Student) init(name string, age int){
this.Name = name
this.Age = age
}
func main(){
var stu Student
//其实本质是(&stu).init("bob", 18),go做了简化
stu.init("bob", 18)
fmt.Println(stu)
}
3.指针receiver和值receiver:本质上和函数的值传递和地址传递是一样的
4.方法的访问控制,通过大小写控制
5.继承:如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的方法,从而实现继承;组合:如果一个struct嵌套了另一个有名结构体,那么这个模式就叫做组合
package main
import "fmt"
type Animal struct{
Name string
}
func (this Animal) Speak(){
fmt.Printf("%v正在咆哮...\n",this.Name)
}
type Dog struct{
Animal
}
type Zoo struct{
Name string
D Dog
}
func main(){
var d1 Dog
d1.Name = "大黄"
d1.Speak()
var zoo Zoo
zoo.Name = "1th"
zoo.D.Speak()
}
View Code
6.多重继承:如果一个struct嵌套了多个匿名结构体,那么这个结构体可以直接访问多个匿名结构体的方法,从而实现了多重继承
接口实现String():
如果一个变量实现了String()这个方法,那么fmt.Printf默认会调用这个变量的String()进行输出
package main
import "fmt"
type Animal struct{
Name string
}
func (this Animal) String() string{
str := fmt.Sprintf("name=[%s]",this.Name)
return str
}
type Dog struct{
Animal
}
func main(){
var d1 Dog
d1.Name = "大黄"
fmt.Printf("%s",d1)
}
View Code