数据结构

WuYiLong原创大约 8 分钟数据结构数组队列

数组

稀疏数组

定义:如果一个二维数组有很多相同的值或0,那么就可以将其转为稀疏数组, 稀疏数组包含几行几列和值,第一行表示的是,原始数组的行和列以及有多少个有效的值

需求: 把一个二维数组转为稀疏数组,并把稀疏数组写入文件里
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {

	// 定义初始化的二维数组
	var arr = [3][3]int{{0, 1, 0}, {0, 0, 3}, {0, 0, 0}}
	fmt.Println("****原始二维数组*****")
	for i := 0; i < len(arr); i++ {
		for j := 0; j < len(arr[i]); j++ {
			fmt.Printf("%v\t", arr[i][j])
		}
		fmt.Println()
	}

	// 判断二维数组中有多少有效的值
	sum := 0
	for _, v := range arr {
		for _, v := range v {
			if v != 0 {
				sum++
			}
		}
	}
	// 获得稀疏数组的行,遍历二维数组确定不为0的数
	var arr2 [][3]int
	a := [3]int{len(arr), len(arr[0]), sum}
	arr2 = append(arr2, a)
	for i := 0; i < len(arr); i++ {
		for j := 0; j < len(arr[i]); j++ {
			if arr[i][j] != 0 {
				a := [3]int{i, j, arr[i][j]}
				arr2 = append(arr2, a)
			}
		}
	}

	fmt.Println("*****转化后的二维数组****")
	file,err :=os.Create("1.txt")
	if err != nil {
		fmt.Printf("err->%v",err)
	}
	//file.WriteString("hello")
	write :=bufio.NewWriter(file)
	for i := 0; i < len(arr2); i++ {
		for j := 0; j < len(arr2[i]); j++ {

			write.WriteString(strconv.FormatInt(int64(arr2[i][j]),10)+"\t")
			fmt.Printf("%v\t", arr2[i][j])
		}
		fmt.Println()
		write.WriteString("\n")

	}

	// 数据写入缓存后,必须调用,才能真正把缓存中的数据写入文件中
	write.Flush()

}

 // 输出结果
 ****原始二维数组*****
0	1	0	
0	0	3	
0	0	0	
*****转化后的二维数组****
3	3	2	 // 分别表示原始数组是个3行3列的数组,并且有2个有效的值
0	1	1	 // 表示有效值1在第1行第2列
1	2	3  // 表示有效值3在第2行第3列

队列

提示

先进先出原则

数组模拟基本队列

// queue.go
// 模拟基本队列
type Queue struct {
	maxSize int    // 表示数组的容量
	array   [5]int // 初始化大小为5的数组
	front   int    // 表示 首部指针,默认-1
	tail    int    // 表示尾部指针,默认-1
}

func NewQueue(maxSize int, front int, tail int) *Queue {

	return &Queue{
		maxSize: maxSize,
		front:   front,
		tail:    tail,
	}
}

func (queue *Queue) AddQueue(n int) (err error) {
	// 判断队列元素是否已满
	if queue.tail == queue.maxSize-1 {
		return errors.New("队列已满,不能再添加元素\n")
	}

	queue.tail++
	queue.array[queue.tail] = n
	return
}

func (queue *Queue) ShowQueue() {
	for i := queue.front+1;i<queue.tail+1;i++ {
		fmt.Printf("array[%v]=%v\n",i,queue.array[i])
	}
}

func (queue *Queue) GetQueue() (value int,err error){
	if queue.front == queue.tail {
		return -1,errors.New("已经没有元素可取了")
	}
	queue.front++
	return queue.array[queue.front],nil
}

// main.go
func main() {
	queue := utils.NewQueue(5,-1,-1)
	var key int
	var val int
	for {
		fmt.Println("1.添加队列元素")
		fmt.Println("2.查看队列")
		fmt.Println("3.取出队列元素")
		fmt.Println("4.退出")
		fmt.Scanln(&key)

		switch key {
		case 1:
			fmt.Println("请输入进入队列的数字")
			fmt.Scanln(&val)
			err := queue.AddQueue(val)
			if err != nil {
				fmt.Println(err)
			}
		case 2:
			queue.ShowQueue()
		case 3:
			v,err := queue.GetQueue()
			if err != nil {
				fmt.Println("err->",err)
			}
			fmt.Printf("取出的元素是->%v\n",v)
		case 4:
			os.Exit(0)
		}
	}
}

使用链表模拟队列


// user.go
// 使用简单链表模拟队列,先进先出
type User struct {
	id       int    // 用户编号
	name     string // 用户名
	age      int    // 用户年龄
	nextUser *User  // 表示连接下一个用户节点
}

func NewUser(id int, name string, age int) *User {
	return &User{
		id:   id,
		name: name,
		age:  age,
	}
}

func (user *User) InsertUser(head *User, newUser *User) {

	for {
		temp := head
		if temp.nextUser == nil {
			temp.nextUser = newUser
			break
		}
		head = temp.nextUser
	}
}

func (user *User) ListUser(head *User) {
	for {
		temp := head
		if temp.nextUser == nil {
			break
		}
		fmt.Printf("[%v,%v,%v]->", temp.nextUser.id, temp.nextUser.name, temp.nextUser.age)
		head = temp.nextUser
	}
	fmt.Println()
}

func (user *User) DeleteUser(head *User) (User, error) {
	temp := head
	if temp.nextUser == nil {
		return User{}, errors.New("已经没有可删除的数据了")
	}
	// 保存下一个元素的值
	nextUserVal := *temp.nextUser
	head.nextUser = temp.nextUser.nextUser // 表示头结点连接下下一个节点,断开的节点等待回收
	return nextUserVal,nil

}

func (user *User) GetUser() {
	fmt.Printf("[%v,%v,%v]\n",user.id,user.name,user.age)
}

// main.go
func main() {
	// 初始化一个头结点
	head := new(utils.User)
	var key int
	var id int
	var name string
	var age int
	for {
		fmt.Println("1.添加队列元素")
		fmt.Println("2.展示队列")
		fmt.Println("3.删除队列元素")
		fmt.Println("4.退出系统")

		fmt.Scanln(&key)
		switch key {
		case 1:
			fmt.Println("输入id号")
			fmt.Scanln(&id)
			fmt.Println("输入姓名")
			fmt.Scanln(&name)
			fmt.Println("输入年龄")
			fmt.Scanln(&age)
			user := utils.NewUser(id,name,age)
			head.InsertUser(head,user)
		case 2:
			head.ListUser(head)
		case 3:
			user,err := head.DeleteUser(head)
			if err != nil {
				fmt.Printf("err->%v\n",err)
				break
			}
			user.GetUser()
		case 4:
			os.Exit(0)
		}
	}
}




链表

单向链表

需求:手写内存数据库,按照id号从小到大排序,完成对数据库的增删改查


// 有序的单向链表(增删改查) person.go
type Person struct {
	id         int     // 用户 编号
	name       string  // 用户名
	age        int     // 用户年龄
	nextPerson *Person // 表示连接下一个用户节点
}

func NewPerson(id int, name string, age int) *Person {
	return &Person{
		id:   id,
		name: name,
		age:  age,
	}
}

func (person *Person) Insert(head *Person, newPerson *Person) {
	for {
		temp := head
		if temp.nextPerson == nil {
			temp.nextPerson = newPerson
			break
		} else if temp.nextPerson.id > newPerson.id {
			newPerson.nextPerson = temp.nextPerson
			temp.nextPerson = newPerson
			break
		}
		head = temp.nextPerson
	}
}

func (person *Person) List(head *Person) {
	for {
		temp := head
		if temp.nextPerson == nil {
			break
		}
		fmt.Printf("[%v,%v,%v]->", temp.nextPerson.id, temp.nextPerson.name, temp.nextPerson.age)
		head = temp.nextPerson
	}
	fmt.Println()
}

// 根据id号删除对应的数据
func (person *Person) Delete(head *Person,id int) (err error) {
	for {
		temp := head
		if temp.nextPerson == nil {
			return errors.New("没有可删除的数据了")
		}

		if id == temp.nextPerson.id {
			temp.nextPerson = temp.nextPerson.nextPerson

			break
		}

		head = temp.nextPerson
	}
	return nil
}

// 根据id号更新对应的数据
func (person *Person) Update(head *Person,newPerson *Person) (err error) {
	for {
		temp := head
		if temp.nextPerson == nil {
			return errors.New("没有数据可更新")
		}
		if newPerson.id == temp.nextPerson.id {
			newPerson.nextPerson = temp.nextPerson.nextPerson
			temp.nextPerson = newPerson
			break
		}
		head = temp.nextPerson
	}
	return nil
}

// main.go
func main() {
// 初始化一个头结点
	head := new(utils.Person)
	var key int
	var id int
	var name string
	var age int
	for {
		fmt.Println("1.添加链表")
		fmt.Println("2.展示链表")
		fmt.Println("3.删除链表")
		fmt.Println("4.更新链表")
		fmt.Println("5.退出系统")
		fmt.Scanln(&key)
		switch key {
		case 1:
			fmt.Println("输入id号")
			fmt.Scanln(&id)
			fmt.Println("输入姓名")
			fmt.Scanln(&name)
			fmt.Println("输入年龄")
			fmt.Scanln(&age)
			person := utils.NewPerson(id,name,age)
			head.Insert(head,person)
		case 2:
			head.List(head)
		case 3:
			fmt.Println("输入要删除的id号")
			var id int
			fmt.Scanln(&id)
			err := head.Delete(head,id)
			if err != nil {
				fmt.Printf("err->%v\n",err)
				break
			}
			fmt.Println("删除成功")
		case 4:
			//fmt.Println("输入要更新的数据")
			fmt.Println("输入id号")
			fmt.Scanln(&id)
			fmt.Println("输入姓名")
			fmt.Scanln(&name)
			fmt.Println("输入年龄")
			fmt.Scanln(&age)
			person := utils.NewPerson(id,name,age)
			err := head.Update(head,person)
			if err != nil {
				fmt.Printf("err->%v\n",err)
				break
			}
			fmt.Println("更新成功")
		case 5:
			os.Exit(0)

		}
	}
}

双向链表

需求:使用双向链表,按照id号从小到大排序,和从大到小排序,并完成查询,列表,删除功能

  • main.go
package main

import (
	"demo/utils"
	"fmt"
	"os"
)

func main() {

	var id int
	var name string
	var age int
	head := new(utils.User)
	for {
		fmt.Println("1.添加用户")
		fmt.Println("2.展示用户列表")
		fmt.Println("3.删除用户")
		fmt.Println("3.退出系统")
		fmt.Println("提示请输入1~4")
		var key int
		fmt.Scanln(&key)
		switch key {
		case 1:
			fmt.Println("请输入用户编号:")
			fmt.Scanln(&id)
			fmt.Println("请输入用户名:")
			fmt.Scanln(&name)
			fmt.Println("请输入年龄:")
			fmt.Scanln(&age)
			user := utils.NewUser(id,name,age)
			head.InsertUser(head,user)
		case 2:
			head.ListUser(head)
			head.ListUser2(head)
		case 3:
			fmt.Println("请输入要删除的id号")
			var id int
			fmt.Scanln(&id)
			err := head.DeleteUser(head,id)
			if err !=nil {
				fmt.Println("err->",err)
			}
			fmt.Println("删除成功")
		case 4:
			os.Exit(0)
		}

	}
}

  • double_link.go
package utils

import (
	"errors"
	"fmt"
)

// 需求:使用双向链表,按照id号从小到大排序,和从大到小排序
// 有序的双向链表(增删改查)
type User struct {
	id       int    // 用户编号
	name     string // 用户名
	age      int    // 用户年龄
	nextUser *User  // 表示下一个用户节点
	preUser *User  // 表示上一个用户节点
}

func NewUser(id int, name string, age int) *User {
	return &User{
		id:   id,
		name: name,
		age:  age,
	}
}

func (user *User) InsertUser(head *User, newUser *User) {

	for {
		temp := head
		if temp.nextUser == nil {
			temp.nextUser = newUser
			newUser.preUser = temp
			break
		} else if temp.nextUser.id > newUser.id {
			newUser.nextUser = temp.nextUser
			temp.nextUser.preUser = newUser
			newUser.preUser = temp
			temp.nextUser = newUser
			break
		}
		head = temp.nextUser
	}
}

func (user *User) ListUser(head *User) {
	for {
		temp := head
		if temp.nextUser == nil {
			break
		}
		fmt.Printf("[%v,%v,%v]->", temp.nextUser.id, temp.nextUser.name, temp.nextUser.age)
		head = temp.nextUser
	}
	fmt.Println("从小到大打印")
}

func (user *User) ListUser2(head *User) {
	for {
		temp := head
		if temp.nextUser == nil {
			break
		}
		head = temp.nextUser
	}

	for {
		temp := head
		if temp.preUser == nil {
			break
		}
		fmt.Printf("[%v,%v,%v]->", temp.id, temp.name, temp.age)
		head = temp.preUser

	}
	fmt.Println("从大到小打印")
}

// 根据id号删除对应的数据
func (user *User) DeleteUser(head *User,id int) (err error) {
	for {
		temp := head
		if temp.nextUser == nil {
			return errors.New("没有对应的id号可删除的数据了")
		}

		if id == temp.id {
			temp.preUser.nextUser = temp.nextUser
			temp.nextUser.preUser = temp.preUser
			break
		}

		head = temp.nextUser
	}
	return nil
}



环形单向链表

### 环形链表
- carNode.go
```go
package utils

import "fmt"

// 单向环形链表
type CarNode struct {
	id   int      // 编号
	name string   // 车名
	next *CarNode // 表示连接下一个
}

func NewCarNode(id int, name string) *CarNode {
	return &CarNode{
		id:   id,
		name: name,
	}
}

func (car *CarNode) AddCar(head *CarNode, newCar *CarNode) {
	// 判断是否是第一个
	if head.next == nil {
		head.id = newCar.id
		head.name = newCar.name
		head.next = head
		return
	}
	temp := head
	for {
		if temp.next == head {
			break
		}
		temp = temp.next
	}
	temp.next = newCar
	newCar.next = head
}

func (car *CarNode) ListCar(head *CarNode) {
	temp := head
	if temp.next == nil {
		fmt.Println("这是一个空链表")
		return
	}

	for {
		if temp.next == head {
			fmt.Printf("[%v,%s,%v,%v]->\n",temp.id,temp.name,temp,temp.next)
			break
		}
		fmt.Printf("[%v,%s,%v,%v]->\n",temp.id,temp.name,temp,temp.next)
		temp = temp.next
	}
}


func (car *CarNode) DeleteCar(head *CarNode,id int)  (err error) {
	temp := head

	if temp.next == nil {
		fmt.Println("这是一个空链表")
		return
	}

	for {
		if temp.id == id {
			temp.name = temp.next.name
			temp.id = temp.next.id
			temp.next = temp.next.next
			break
		}
		if temp.next.next == head {
			if temp.next.id ==id {
				temp.next = head
				break
			}
		}
		temp = temp.next
	}
	return nil
}
  • main.go
package main

import (
	"demo/utils"
	"fmt"
	"os"
)
func main() {
	var id int
	var name string
	//var age int
	head := new(utils.CarNode)
	for {
		fmt.Println("1.添加车")
		fmt.Println("2.展示车列表")
		fmt.Println("3.删除列表")
		fmt.Println("4.退出系统")
		fmt.Println("提示请输入1~3")
		var key int
		fmt.Scanln(&key)
		switch key {
		case 1:
			fmt.Println("请输入车编号:")
			fmt.Scanln(&id)
			fmt.Println("请输入车名:")
			fmt.Scanln(&name)
			car := utils.NewCarNode(id,name)
			head.AddCar(head,car)
		case 2:
			head.ListCar(head)
		case 3:
			fmt.Println("输入要删除的id")
			var id int
			fmt.Scanln(&id)
			err := head.DeleteCar(head,id)
			if err != nil {
				fmt.Println("err->",err)
			}
			fmt.Println("删除成功")
		case 4:
			os.Exit(0)
		}

	}
}

约瑟夫问题

设编号为1,2,....n的n个人围坐一圈,约定编号为k(1<=k<=n)的人,从1开始报数,数到m个人出列,它的下一位又从一开始报数,数到m的那个人又出列,依此类推,直到所有的人出列为止,由此产生一个出队编号的序列。

上次编辑于:
贡献者: wuyilong