Go语言数据结构—稀疏数组

介绍

如果一个数组中非零个数远远小于数组元素个数,且非零元素分布没有规律,当这样的数组进行存储时,因为很多元素都是为0的,直接存储的话,会浪费掉很多空间。这时候可以数组转化为稀疏数组,然后进行存储。那么怎么进行转换呢?

		{
    
    0, 1, 0, 0, 0},
		{
    
    1, 0, 0, 0, 0},
		{
    
    0, 0, 1, 0, 0},
		{
    
    0, 0, 0, 0, 0},
		{
    
    0, 0, 0, 0, 1},
	
以行上面这个数组为例:
	1. 首先记录数组的行、列、几个非零的元素(row、col、value)
	2. 再记录数组存储非零元素的位置和值 (row、col、value)
	3. 最后把row、col、value存储到稀疏数组,并进行保存
	

普通数组转为稀疏数组

函数有两个参数:1. 要转换的数组,2. 转换后稀疏数组的存储路径

func arrayToSparseArray(array [][]int, filePath string) (err error) {
    
    

	// 1. 获取稀疏数组的行和列,及非零值的个数
	rowL := len(array)
	colL := len(array[0])
	num := 0
	// 遍历二维数组, 找非零值的数量
	for _, v1 := range array {
    
    
		for _, v2 := range v1 {
    
    
			if v2 != 0 {
    
    
				num++
			}
		}
	}

	// 声明一个Node的切片,为Node切片类型
	//  Node切片有row、col、value三个属性,用来存储每个非零值元素的信息
	var sparseArr []Node

	// 初始化数组
	node := Node{
    
    
		rowL,
		colL,
		num,
	}
	sparseArr = append(sparseArr, node)

	// 遍历稀疏数组,得到每个非零值信息,并保存到array
	for i, v1 := range array {
    
    
		for j, v2 := range v1 {
    
    
			if v2 != 0 {
    
    
				node = Node{
    
    i, j, v2}
				sparseArr = append(sparseArr, node)
			}
		}
	}

	fmt.Println("转换后的数组为:")
	for _, v := range sparseArr {
    
    
		fmt.Printf("%d %d %d\n", v.row, v.col, v.value)
	}

	// 把转换后的保存到本地
	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
    
    
		return
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	for _, value := range sparseArr {
    
    
		data := fmt.Sprintf("%d %d %d\n", value.row, value.col, value.value)
		_, err = writer.WriteString(data)
		if err != nil {
    
    
			return
		}
	}
	writer.Flush()

	fmt.Println("写入数据成功")
	return
}

稀疏数组转为普通数组

函数参数:稀疏文件的存储路径
函数返回值:转换后的普通数组,错误信息

func sparseArrToArr(filePath string) (array [][]int, error error) {
    
    
	// 读取本地文件, 获取到稀疏数组
	file, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
	if err != nil {
    
    
		error = err
		return
	}
	defer file.Close()

	reader := bufio.NewReader(file)
	// 生成稀疏数组
	node := Node{
    
    }
	var row, col, value int
	var sparseArr []Node
	for {
    
    
		data, err := reader.ReadString('\n')
		if err != nil && err != io.EOF {
    
    
			error = err
			return
		}
		if err == io.EOF {
    
    
			break
		}
		data2 := strings.Fields(data)
		// 这里读取到的数据为string类型,要转换为int类型
		row, err = strconv.Atoi(data2[0])
		if err != nil {
    
    
			error = err
			return
		}
		col, err = strconv.Atoi(data2[1])
		if err != nil {
    
    
			error = err
			return
		}
		value, err = strconv.Atoi(data2[2])
		if err != nil {
    
    
			error = err
			return
		}
		node = Node{
    
    row, col, value}
		sparseArr = append(sparseArr, node)
	}

	// 遍历稀疏数组,把稀疏数组转化为二维切片
	for i, v := range sparseArr {
    
    
		// 稀疏的第0号元素为数组的结构信息
		if i == 0 {
    
    
			row = v.row
			col = v.col
			array = make([][]int, row)
			for i := range array {
    
    
				array[i] = make([]int, col)
			}	
			continue
		}
		// 为数组对应的位置填充对应的值
		array[v.row][v.col] = v.value
	}

	// 返回数组及错误信息
	return array, err
}

测试

func main() {
    
    

	filePath := "./sparseArray.txt"

	// 测试数组
	array := [][]int{
    
    
		{
    
    0, 1, 0, 0, 0},
		{
    
    1, 0, 0, 0, 0},
		{
    
    0, 0, 1, 0, 0},
		{
    
    0, 0, 0, 0, 0},
		{
    
    0, 0, 0, 0, 1},
	}

	err := arrayToSparseArray(array, filePath)
	if err != nil {
    
    
		fmt.Println(err)
		return
	}

	data, err := sparseArrToArr(filePath)
	if err != nil {
    
    
		fmt.Println(err)
		return
	}
	for _, v := range data {
    
    
		fmt.Println(v)
	}
}

最后

个人感觉稀疏数组不仅仅可以用于棋盘中,别的很多地方都能使用到,而且数组中非零元素也不一定非要为1才行。代码中还使用了切片,发现切片确实比数组灵活了许多。完整代码在这里:https://github.com/bigzoro/go_algorithm

如果代码中有不足之处,欢迎评论区指出。

猜你喜欢

转载自blog.csdn.net/qq_31639829/article/details/120761791