块状链表实现BigString大字符串操作(golang)

news2025/1/12 23:00:10

前言

块状链表是介于链表和数组之间的数据结构,能够在 O ( n ) O(\sqrt{n}) O(n )时间内完成插入、删除、访问操作。

数据结构如图所示。假设最大容量为 n n n, 则它有一个长度为 s = n s=\sqrt{n} s=n 的链表。链表中每个结点是一个长度为 2 × n 2 \times \sqrt{n} 2×n 的数组。

参考:https://oi-wiki.org/ds/block-list/
在这里插入图片描述
实现时,有两个细节需要注意:

  • 初始时,只有一个链表结点。随着数据越来越多,当某个结点内数组装满后,将分裂成两个结点。

  • 删除数据后,如果数据所在结点为空,则需要删除结点(链表首元结点不用删除)。

本文以BigString为例进行实现。

实现

使用golang实现如下字符串功能:

  • Append(str) 向字符串尾部添加一个字符串
  • Size() 获取字符串长度
  • Insert(index, char) 向字符串某个位置插入一个字符
  • Erase(index) 删除某个位置的字符
  • At(index) 获了某个位置的字符
  • Set(index, char) 设置某个位置的字符
package main

import (
	"fmt"
	"math"
)

type _Node struct {
	next *_Node
	size int
	data []rune
}

type BigString struct {
	head    *_Node // 没有哨兵,直接就是首元结点
	size    int    // 字符串大小
	bukSize int    // 分组大小
	maxSize int    // 最大字符大小
}

func NewBigString(maxLen int) *BigString {
	if maxLen < 10 {
		maxLen = 10
	}
	// 计算分段长度
	s := int(math.Sqrt(float64(maxLen)))
	return &BigString{
		head:    &_Node{nil, 0, make([]rune, 2*s)},
		size:    0,
		bukSize: s,
		maxSize: maxLen,
	}
}

func (this *BigString) String() string {
	var str string
	for node := this.head; node != nil; node = node.next {
		for i := 0; i < node.size; i++ {
			str += string(node.data[i])
		}
	}
	return str
}

/*
*
在尾部插入字符
*/
func (this *BigString) Append(chars string) {
	for _, char := range chars {
		this.Insert(this.size, rune(char))
	}
}

/*
*
在尾部插入字符
*/
func (this *BigString) Size() int {
	return this.size
}

/*
*
在指定位置插入字符
*/
func (this *BigString) Insert(index int, char rune) {
	if this.size < this.maxSize && index >= 0 && index <= this.size {
		pos := -1
		for node := this.head; node != nil; node = node.next {
			if index <= node.size+pos+1 {
				insertPos := index - pos - 1 // 0 1 2 3 4 | 5 6 7   , index = 6,
				for j := node.size; j > insertPos; j-- {
					node.data[j] = node.data[j-1]
				}
				node.data[insertPos] = char
				node.size++
				// 结点分裂开
				if node.size == len(node.data) {
					node2 := &_Node{node.next, this.bukSize, make([]rune, 2*this.bukSize)}
					for j := 0; j < this.bukSize; j++ {
						node2.data[j] = node.data[j+this.bukSize]
					}
					node.size -= this.bukSize
					node.next = node2
				}
				break
			}
			pos += node.size
		}
		this.size++
	}
}

/*
*
删除指定位置字符
*/
func (this *BigString) Erase(index int) {
	if index >= 0 && index < this.size {
		pos := -1
		var pre *_Node = nil
		for node := this.head; node != nil; node = node.next {
			if index <= node.size+pos {
				deletePos := index - pos - 1
				for j := deletePos + 1; j < node.size; j++ {
					node.data[j-1] = node.data[j]
				}
				node.size--

				// 清理空结点
				if node.size == 0 {
					if node != this.head {
						pre.next = pre.next.next
					}
				}

				break
			}
			pos += node.size
			pre = node
		}
		this.size--
	}
}

/*
*
获取指定位置字符
*/
func (this *BigString) At(index int) rune {
	if index >= 0 && index < this.size {
		pos := -1
		for node := this.head; node != nil; node = node.next {
			if index <= node.size+pos {
				atPos := index - pos - 1
				return node.data[atPos]
			}
			pos += node.size
		}
	}
	return 0
}

/*
*
设置指定位置字符
*/
func (this *BigString) Set(index int, char rune) {
	if index >= 0 && index < this.size {
		pos := -1
		for node := this.head; node != nil; node = node.next {
			if index <= node.size+pos {
				atPos := index - pos - 1
				node.data[atPos] = char
				break
			}
			pos += node.size
		}
	}
}

测试

测试结果与测试代码如下。结果表明实现是正确的。

在这里插入图片描述

str := NewBigString(225)

	// 测试 Append, Insert, String
	fmt.Println("【测试 Append, Insert, String】")
	str.Append("hello world! my name is cloudea. this is my first big string implementation!\n")
	str.Append("世界 你好! 我的我名字是克劳迪亚。这是我的第一个大字符串实现哦!\n")
	fmt.Println(str)
	str.Insert(0, '*')
	str.Insert(78, '#')
	fmt.Println(str)
	for i := 0; i < 40; i++ {
		str.Insert(100, '$')
	}
	fmt.Println(str)

	// 测试Erase
	fmt.Println("【测试 Erase】")
	for i := 0; i < 40; i++ {
		str.Erase(100)
	}
	fmt.Println(str)

	// 测试测试At 和 Set
	fmt.Println("【测试At 和 Set】")
	str.Set(99, '你')
	str.Set(100, '呀')
	str.Set(101, 'd')
	str.Set(102, '二')
	str.Set(103, '个')
	for i := 0; i < str.Size(); i++ {
		fmt.Print(string(str.At(i)))
	}
	fmt.Println()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/491913.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#_各类应用程序

目录 前言 1. 第一个程序&#xff1a;Hello&#xff0c;World&#xff01; 1.1 Console 1.2 Windows Forms 1.3 WPF&#xff08;Windows Presentation Foundation&#xff09; 1.4 ASP.NET Web Forms 1.5 ASP.NET MVC(Model - View - Controller) 1.6 Windows Store A…

Tuxera NTFS2023Mac专业NTFS驱动软件 解决Mac不能写入移动硬盘U盘问题 管理修复磁盘

Tuxera NTFS2023Mac专业NTFS驱动软件 解决Mac不能写入移动硬盘U盘问题 管理修复磁盘问题! NTFS For Mac2023是一款功能强大的MAC读写软件。NTFS For Mac可以帮助用户对磁盘进行日常管理&#xff0c;如果用户电脑的磁盘有问题&#xff0c;可以使用该软件进行修复&#xff0c;延…

Chatgpt系列(一) 如何使用chatgpt

系列文章目录 第一章: 如何使用chatgpt 第二章: chatgpt的概述 第三章: langchain入门 第四章: index 第五章: prompt 目录 系列文章目录 前言 一、LLM是什么&#xff1f; 二、使用步骤 1.学习地址 2.阅读内容重点的介绍 2.答复 读入数据 总结 系列文章目录前言一…

0基础学Java必备的50个知识点

1、编写&#xff1a;编写的Java代码保存在以“.java”结尾的源文件中。 2、编译&#xff1a;使用javac.exe命令编译java源文件&#xff0c;生成字节码文件。 格式&#xff1a;javac 源文件名.java 3、运行&#xff1a;使用java.exe命令解释运行字节码文件。格式&#xff1a;…

Linux笔记3

目录 一、root用户1.su命令2.sudo命令 二、vi/vim编译器1.三种工作模式2.命令模式3.底线命令模式 三、用户和用户组1.用户组管理2.用户管理3.getent命令 四、权限1.查看权限控制信息2.chmod 命令3.chown 命令 五、常用快捷键1.Ctrlc2.Ctrld3.历史命令4.光标移动快捷键 一、root…

亚马逊云科技和安恒信息,发布云原生SaaS主机安全和云原生堡垒机

4月19日&#xff0c;安恒信息首次举行了以“新见未来 实现梦想”为主题的年度新品发布会。来自产业界、投资界、财经界、媒体界等多方代表共同见证了本次发布会。这也是安恒信息自成立以来&#xff0c;首次大规模、高密度地发布新品。 联合产品发布 云原生SaaS主机安全与云原…

Linux 指令(一)+完整思维导图+实图例子+深入细节+通俗易懂建议收藏

绪论 在上一章&#xff0c;我们已经将Linux环境的安装起来了&#xff0c;从本章开始&#xff0c;我们将正式的进入到Linux的学习&#xff0c;Linux的学习还是比较的枯燥无味的&#xff0c;但我们要吃得苦中苦&#xff0c;让我们一起加油&#xff0c;进大厂拿到心仪的offer&…

黑马程序员-职工管理系统实战-附加源码Git

1、管理系统需求 职工管理系统可以用来管理公司内所有员工的信息 本教程主要利用C来实现一个基于多态的职工管理系统 公司中职工分为三类&#xff1a;普通员工、经理、老板&#xff0c;显示信息时&#xff0c;需要显示职工编号、职工姓名、职工岗位、以及职责 普通员工职责…

Redis在项目实践中的问题解决方案汇总

前言 无论是在开发过程中还是在准备跑路的面试过程中&#xff0c;和Redis相关的话题&#xff0c;难免会涉及到四个特殊场景&#xff1a;缓存穿透、缓存雪崩、缓存击穿以及数据一致性。 虽然在作为服务缓存层的时候Redis确实能极大减少服务端的请求压力&#xff0c;但是如果在…

企业组织管理神器:红海云可视化组织管理功能深度解析

在当前的VUCA时代&#xff0c;企业需要保持敏捷以应对变革和不确定性。组织架构作为承载战略目标的重要工具&#xff0c;如果无法敏捷调整&#xff0c;会直接影响企业战略的成功落地。但组织架构的设计和调整会触及其他业务&#xff0c;包括岗位、编制、人员与汇报关系等信息变…

优先级队列(大根堆与小根堆)

优先级队列&#xff08;大根堆与小根堆&#xff09; 文章目录 优先级队列&#xff08;大根堆与小根堆&#xff09;堆的介绍模拟堆以数组模型为例&#xff0c;创建堆向下调整&#xff08;shiftDown&#xff09;入队&#xff08;push&#xff09;及向上调整&#xff08;shiftUp&a…

java获取文件夹下所有文件名

在进行 Java编程的过程中&#xff0c;我们会经常使用到文件夹下的所有文件名。有时候可能不太熟悉 Java编程的小伙伴们会发现&#xff0c;在代码中没有获取到所有的文件名&#xff0c;那么这个时候我们应该怎么去获取到这些文件呢&#xff1f;在进行 Java编程的过程中&#xff…

《花雕学AI》31:ChatGPT--用关键词/咒语/提示词Prompt激发AI绘画的无限创意!

你有没有想过用AI来画画&#xff1f;ChatGPT是一款基于GPT-3的聊天模式的AI绘画工具&#xff0c;它可以根据你输入的关键词/咒语/提示词Prompt来生成不同风格和主题的画作。Prompt是一些简短的文字&#xff0c;可以用来指导ChatGPT的创作过程。在这篇文章中&#xff0c;我将展示…

2个月快速通过PMP证书的经验分享

01 PMP证书是什么&#xff1f; 指的是项目管理专业人士资格认证。它是由美国项目管理协会&#xff08;Project Management Institute(简称PMI)&#xff09;发起的&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试。其目的是为了给项目管理人员提供统一的…

Redis【性能 02】Redis-5.0.14伪集群和Docker集群搭建及延迟和性能测试(均无法提升性能)

伪集群及Docker集群搭建测试流程 1.伪集群搭建1.1 环境1.2 搭建1.2.1 集群配置1.2.2 生成其他5个节点配置1.2.3 启动并验证节点状态1.2.4 创建集群1.2.5 集群信息 1.3 测试 2.Docker集群2.1 环境2.2 搭建2.2.1 创建专用网络2.2.2 生成配置文件2.2.3 容器启动及验证2.2.4 创建集…

NIST SP 800-193: BIOS 平台固件弹性指南

NIST SP 800-147&#xff0c;BIOS 保护指南 ( NIST SP 800-147 [1]、NIST SP 800-147B [2]&#xff09;解决了 BIOS 的保护问题 可从此处免费获得&#xff1a; https://doi.org/10.6028/NIST.SP.800-193 摘要 此文档提供了关于支持平台固件和数据对抗潜在地具有破坏性的攻…

python的 __init__.py文件中使用__all__变量

在Python的包&#xff08;Package&#xff09;中&#xff0c;init.py文件可以被用作初始化包的脚本。这个文件会在包被导入时自动执行。同时&#xff0c;init.py文件中的__all__变量也可以被用来限制包中可导入的模块、类或方法。具体来说&#xff0c;__all__变量应该是一个列表…

项目上线 | 兰精携手盖雅工场,数智驱动绿色转型

近年来&#xff0c;纺织纤维行业零碳行动如火如荼。作为低碳环保消费新时尚引领者&#xff0c;同时也是纤维领域隐形冠军&#xff0c;兰精在推进绿色发展的同时&#xff0c;也在不断向内探索企业数字化转型之道&#xff0c;以此反哺业务快速扩张。 数智转型&#xff0c;管理先…

计算机网络面试题(上)

1.TCP/IP 网络模型有哪几层&#xff1f; TCP/IP 网络通常是由上到下分成 4 层&#xff0c;分别是应用层&#xff0c;传输层&#xff0c;网络层和网络接口层。 每一层的封装格式&#xff1a; 网络接口层的传输单位是帧&#xff08;frame&#xff09;&#xff0c;IP 层的传输单位…

探究肺癌患者的CT图像的图像特征并构建一个诊断模型

目标效果图操作说明代码 目标 探究肺癌患者的CT图像的图像特征并构建一个诊断模型 效果图 操作说明 代码中我以建立10张图为例&#xff0c;多少你自己定 准备工作&#xff1a; 1.准备肺癌或非肺癌每个各10张图&#xff0c;在本地创建一个名为“data”的文件夹&#xff0c;用…