本篇文章我们用go来实现红黑树,部分参考资料如下:

1.节点定义

type RBNode struct {
color uint8
key Type
left, right, parent *RBNode
} type RBRoot struct {
node *RBNode
}

2.树的遍历

// 前序遍历
func PreTraverse(p *RBNode) {
if p != nil {
fmt.Printf("%d ", p.key)
PreTraverse(p.left)
PreTraverse(p.right)
}
} // 中序遍历
func InTraverse(p *RBNode) {
if p != nil {
InTraverse(p.left)
fmt.Printf("%d ", p.key)
InTraverse(p.right)
}
} // 前序遍历
func PostTraverse(p *RBNode) {
if p != nil {
PostTraverse(p.left)
PostTraverse(p.right)
fmt.Printf("%d ", p.key)
}
}

3.树的旋转

/*
* 对红黑树的节点(x)进行左旋转
情况1:
* x y
* / \ --(左旋)--> / \
* lx y x ry
* / \ / \
* ly ry lx ly
情况2:
* px px
* / /
* x y
* / \ --(左旋)--> / \
* lx y x ry
* / \ / \
* ly ry lx ly
情况3:
* px px
* \ \
* x y
* / \ --(左旋)--> / \
* lx y x ry
* / \ / \
* ly ry lx ly
*
*/
func left_rotate(root *RBRoot, x *RBNode) {
var y *RBNode = x.right // ly 和 x 的关系
x.right = y.left
if y.left != nil {
y.left.parent = x
} // px 和 y 的关系(要考虑px为空,即x为根节点的情况)
y.parent = x.parent
if x.parent == nil {
root.node = y
} else {
if x.parent.left == x {
x.parent.left = y
} else {
x.parent.right = y
}
} // y 和 x 的关系
y.left = x
x.parent = y } /*
* 对红黑树的节点(y)进行右旋转
* 情况1:
* y x
* / \ --(右旋)--> / \
* x ry lx y
* / \ / \
* lx rx rx ry
* 情况2:
* py py
* / /
* y x
* / \ --(右旋)--> / \
* x ry lx y
* / \ / \
* lx rx rx ry
* 情况3:
* py py
* \ \
* y x
* / \ --(右旋)--> / \
* x ry lx y
* / \ / \
* lx rx rx ry
*/
func right_rotate(root *RBRoot, y *RBNode) {
var x *RBNode = y.left // rx 和 y 的关系
y.left = x.right
if x.right != nil {
x.right.parent = y
} // py 和 x 的关系(要考虑py为空,即y为根节点的情况)
x.parent = y.parent
if y.parent == nil {
root.node = x
} else {
if y.parent.right == y {
y.parent.right = x
} else {
y.parent.left = x
}
} // y 和 x 的关系
x.right = y
y.parent = x
}

4.添加节点

// 添加节点:将节点(node)插入到红黑树中
func Add(root *RBRoot, node *RBNode) {
var y *RBNode
var x *RBNode = root.node // 找到node应插入位置的父节点
for x != nil {
y = x
if node.key < x.key {
x = x.left
} else {
x = x.right
}
}
// 设置node和父节点的关系
node.parent = y
if y != nil {
if node.key < y.key {
y.left = node
} else {
y.right = node
}
} else {
root.node = node
}
// 设置节点为红色
node.color = RED
// 修正为红黑树
add_fixup(root, node) } // 红黑树插入修正
func add_fixup(root *RBRoot, node *RBNode) {
var parent, gparent *RBNode // 若“父节点存在,并且父节点的颜色是红色”
for parent=node.parent; parent != nil && rb_is_red(parent); {
gparent = parent.parent //若“父节点”是“祖父节点的左孩子”
if parent == gparent.left {
var uncle *RBNode = gparent.right
// Case 1条件:叔叔节点是红色
if uncle != nil && rb_is_red(uncle) {
rb_set_black(uncle)
rb_set_black(parent)
rb_set_red(gparent)
node = gparent
continue
}
// Case 2条件:叔叔是黑色,且当前节点是右孩子
if parent.right == node {
left_rotate(root, parent)
var tmp *RBNode = parent
parent = node
node = tmp
}
// Case 3条件:叔叔是黑色,且当前节点是左孩子。
rb_set_black(parent)
rb_set_red(gparent)
right_rotate(root, gparent)
} else {
//若“父节点”是“祖父节点的右孩子” var uncle *RBNode = gparent.left
// Case 1条件:叔叔节点是红色
if uncle != nil && rb_is_red(uncle) {
rb_set_black(uncle)
rb_set_black(parent)
rb_set_red(gparent)
node = gparent
continue
}
// Case 2条件:叔叔是黑色,且当前节点是左孩子
if parent.left == node {
right_rotate(root, parent)
var tmp *RBNode = parent
parent = node
node = tmp
}
// Case 3条件:叔叔是黑色,且当前节点是右孩子。
rb_set_black(parent)
rb_set_red(gparent)
left_rotate(root, gparent)
}
}
// 将根节点设为黑色
rb_set_black(root.node)
}

5.删除节点

func Delete(root *RBRoot, node *RBNode) {
var child, parent *RBNode
var color uint8 // 被删除节点的"左右孩子都不为空"的情况。
if node.left != nil && node.right != nil {
// 获取后继节点
var replace *RBNode = node.right
for replace.left != nil {
replace = replace.left
} // "node节点"不是根节点
if node.parent != nil {
if node.parent.left == node {
node.parent.left = replace
} else {
node.parent.right = replace
}
} else {
// "node节点"是根节点,更新根节点。
root.node = replace
}
// child是"取代节点"的右孩子,也是需要"调整的节点"。
// "取代节点"肯定不存在左孩子!因为它是一个后继节点。
child = replace.right
parent = replace.parent
// 保存"取代节点"的颜色(注意这里删掉的是node节点,但实际删掉的颜色是replace的)
color = replace.color // "被删除节点"是"它的后继节点的父节点"
if parent == node {
parent = replace
} else {
// child不为空
if child != nil {
child.parent = parent
}
parent.left = child replace.right = node.right
node.right.parent = replace
} replace.parent = node.parent
replace.color = node.color
replace.left = node.left
node.left.parent = replace if color == BLACK {
delete_fixup(root, child, parent)
} return
} if node.left != nil {
child = node.left
} else {
child = node.right
} parent = node.parent
color = node.color // 保存"取代节点"的颜色 if child != nil {
child.parent = parent
} // "node节点"不是根节点
if parent != nil {
if parent.left == node {
parent.left = child
} else {
parent.right = child
}
} else {
root.node = child
} if color == BLACK {
delete_fixup(root, child, parent)
} } func delete_fixup(root *RBRoot, node *RBNode, parent *RBNode) {
var other *RBNode for (node == nil || rb_is_black(node)) && node != root.node {
// node是父节点的左孩子
if parent.left == node {
other = parent.right
// Case 1: node的兄弟节点是红色的
if rb_is_red(other) {
rb_set_black(other)
rb_set_red(parent)
left_rotate(root, parent)
other = parent.right
}
// Case 2: node的兄弟w是黑色,且w的俩个孩子也都是黑色的
if (other.left == nil || rb_is_black(other.left)) && (other.right == nil || rb_is_black(other.right)) {
rb_set_red(other)
node = parent
parent = node.parent
} else {
// Case 3: node的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
if other.right == nil || rb_is_black(other.right) {
rb_set_black(other.left)
rb_set_red(other)
right_rotate(root, other)
other = parent.right
}
// Case 4: node的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
other.color = parent.color
rb_set_black(parent)
rb_set_black(other.right)
left_rotate(root, parent)
node = root.node
break
}
} else {
other = parent.left
// Case 1: node的兄弟w是红色的
if rb_is_red(other) {
rb_set_black(other)
rb_set_red(parent)
right_rotate(root, parent)
other = parent.left
}
// Case 2: node的兄弟w是黑色,且w的俩个孩子也都是黑色的
if (other.left == nil || rb_is_black(other.left)) && (other.right == nil || rb_is_black(other.right)) {
rb_set_red(other)
node = parent
parent = node.parent
} else {
// Case 3: node的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
if other.left == nil || rb_is_black(other.left) {
rb_set_black(other.right)
rb_set_red(other)
left_rotate(root, other)
other = parent.left
}
// Case 4: node的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
other.color = parent.color
rb_set_black(parent)
rb_set_black(other.left)
right_rotate(root, parent)
node = root.node
break
}
}
} if node != nil {
rb_set_black(node)
}
}

6.完整代码

package main

import "fmt"

const RED  = 0
const BLACK = 1 type Type int type RBNode struct {
color uint8
key Type
left, right, parent *RBNode
} type RBRoot struct {
node *RBNode
} func rb_is_red(node *RBNode) bool {
return node.color == RED
} func rb_is_black(node *RBNode) bool {
return node.color == BLACK
} func rb_set_red(node *RBNode) {
node.color = RED
} func rb_set_black(node *RBNode) {
node.color = BLACK
} // 前序遍历
func PreTraverse(p *RBNode) {
if p != nil {
fmt.Printf("%d ", p.key)
PreTraverse(p.left)
PreTraverse(p.right)
}
} // 中序遍历
func InTraverse(p *RBNode) {
if p != nil {
InTraverse(p.left)
fmt.Printf("%d ", p.key)
InTraverse(p.right)
}
} // 前序遍历
func PostTraverse(p *RBNode) {
if p != nil {
PostTraverse(p.left)
PostTraverse(p.right)
fmt.Printf("%d ", p.key)
}
} // 查找键值为key的节点
func Find(node *RBNode, key Type) *RBNode {
for node != nil && node.key != key {
if key < node.key {
node = node.left
} else {
node = node.right
}
}
return node
} // 打印红黑树
func Print(node *RBNode, key Type, direction int) {
if node != nil {
if direction == 0 {
fmt.Printf("%2d(B) is root\n", node.key)
} else {
var color, _direction string
if rb_is_red(node) {
color = "R"
} else {
color = "B"
}
if direction == 1 {
_direction = "right"
} else {
_direction = "left"
}
// TODO: 这里key 和 %d 的关系
fmt.Printf("%2d(%s) is %2d's %6s child\n", node.key, color, key, _direction)
}
Print(node.left, node.key, -1)
Print(node.right, node.key, 1)
}
} // 打印根节点的所有路径(检测两条红黑树特性)
func PrintRoute(node *RBNode) {
if node == nil {
return
}
if node.left == nil && node.right == nil {
var tmp *RBNode = node
var num int
for tmp != nil {
var color string
if rb_is_red(tmp) {
color = "R"
} else {
color = "B"
num++
}
fmt.Printf("%2d(%s)-->", tmp.key, color)
if tmp.parent != nil && (tmp.color == RED && tmp.parent.color == RED) {
fmt.Println("检测到违反红黑树特性:红节点的子节点是红节点")
}
tmp = tmp.parent
}
fmt.Printf("共 %d 个黑节点\n", num)
}
PrintRoute(node.left)
PrintRoute(node.right)
} /*
* 对红黑树的节点(x)进行左旋转
情况1:
* x y
* / \ --(左旋)--> / \
* lx y x ry
* / \ / \
* ly ry lx ly
情况2:
* px px
* / /
* x y
* / \ --(左旋)--> / \
* lx y x ry
* / \ / \
* ly ry lx ly
情况3:
* px px
* \ \
* x y
* / \ --(左旋)--> / \
* lx y x ry
* / \ / \
* ly ry lx ly
*
*/
func left_rotate(root *RBRoot, x *RBNode) {
var y *RBNode = x.right // ly 和 x 的关系
x.right = y.left
if y.left != nil {
y.left.parent = x
} // px 和 y 的关系(要考虑px为空,即x为根节点的情况)
y.parent = x.parent
if x.parent == nil {
root.node = y
} else {
if x.parent.left == x {
x.parent.left = y
} else {
x.parent.right = y
}
} // y 和 x 的关系
y.left = x
x.parent = y } /*
* 对红黑树的节点(y)进行右旋转
* 情况1:
* y x
* / \ --(右旋)--> / \
* x ry lx y
* / \ / \
* lx rx rx ry
* 情况2:
* py py
* / /
* y x
* / \ --(右旋)--> / \
* x ry lx y
* / \ / \
* lx rx rx ry
* 情况3:
* py py
* \ \
* y x
* / \ --(右旋)--> / \
* x ry lx y
* / \ / \
* lx rx rx ry
*/
func right_rotate(root *RBRoot, y *RBNode) {
var x *RBNode = y.left // rx 和 y 的关系
y.left = x.right
if x.right != nil {
x.right.parent = y
} // py 和 x 的关系(要考虑py为空,即y为根节点的情况)
x.parent = y.parent
if y.parent == nil {
root.node = x
} else {
if y.parent.right == y {
y.parent.right = x
} else {
y.parent.left = x
}
} // y 和 x 的关系
x.right = y
y.parent = x
} // 添加节点:将节点(node)插入到红黑树中
func Add(root *RBRoot, node *RBNode) {
var y *RBNode
var x *RBNode = root.node // 找到node应插入位置的父节点
for x != nil {
y = x
if node.key < x.key {
x = x.left
} else {
x = x.right
}
}
// 设置node和父节点的关系
node.parent = y
if y != nil {
if node.key < y.key {
y.left = node
} else {
y.right = node
}
} else {
root.node = node
}
// 设置节点为红色
node.color = RED
// 修正为红黑树
add_fixup(root, node) } // 红黑树插入修正
func add_fixup(root *RBRoot, node *RBNode) {
var parent, gparent *RBNode // 若“父节点存在,并且父节点的颜色是红色”
for parent=node.parent; parent != nil && rb_is_red(parent); {
gparent = parent.parent //若“父节点”是“祖父节点的左孩子”
if parent == gparent.left {
var uncle *RBNode = gparent.right
// Case 1条件:叔叔节点是红色
if uncle != nil && rb_is_red(uncle) {
rb_set_black(uncle)
rb_set_black(parent)
rb_set_red(gparent)
node = gparent
continue
}
// Case 2条件:叔叔是黑色,且当前节点是右孩子
if parent.right == node {
left_rotate(root, parent)
var tmp *RBNode = parent
parent = node
node = tmp
}
// Case 3条件:叔叔是黑色,且当前节点是左孩子。
rb_set_black(parent)
rb_set_red(gparent)
right_rotate(root, gparent)
} else {
//若“父节点”是“祖父节点的右孩子” var uncle *RBNode = gparent.left
// Case 1条件:叔叔节点是红色
if uncle != nil && rb_is_red(uncle) {
rb_set_black(uncle)
rb_set_black(parent)
rb_set_red(gparent)
node = gparent
continue
}
// Case 2条件:叔叔是黑色,且当前节点是左孩子
if parent.left == node {
right_rotate(root, parent)
var tmp *RBNode = parent
parent = node
node = tmp
}
// Case 3条件:叔叔是黑色,且当前节点是右孩子。
rb_set_black(parent)
rb_set_red(gparent)
left_rotate(root, gparent)
}
}
// 将根节点设为黑色
rb_set_black(root.node)
} func Delete(root *RBRoot, node *RBNode) {
var child, parent *RBNode
var color uint8 // 被删除节点的"左右孩子都不为空"的情况。
if node.left != nil && node.right != nil {
// 获取后继节点
var replace *RBNode = node.right
for replace.left != nil {
replace = replace.left
} // "node节点"不是根节点
if node.parent != nil {
if node.parent.left == node {
node.parent.left = replace
} else {
node.parent.right = replace
}
} else {
// "node节点"是根节点,更新根节点。
root.node = replace
}
// child是"取代节点"的右孩子,也是需要"调整的节点"。
// "取代节点"肯定不存在左孩子!因为它是一个后继节点。
child = replace.right
parent = replace.parent
// 保存"取代节点"的颜色(注意这里删掉的是node节点,但实际删掉的颜色是replace的)
color = replace.color // "被删除节点"是"它的后继节点的父节点"
if parent == node {
parent = replace
} else {
// child不为空
if child != nil {
child.parent = parent
}
parent.left = child replace.right = node.right
node.right.parent = replace
} replace.parent = node.parent
replace.color = node.color
replace.left = node.left
node.left.parent = replace if color == BLACK {
delete_fixup(root, child, parent)
} return
} if node.left != nil {
child = node.left
} else {
child = node.right
} parent = node.parent
color = node.color // 保存"取代节点"的颜色 if child != nil {
child.parent = parent
} // "node节点"不是根节点
if parent != nil {
if parent.left == node {
parent.left = child
} else {
parent.right = child
}
} else {
root.node = child
} if color == BLACK {
delete_fixup(root, child, parent)
} } func delete_fixup(root *RBRoot, node *RBNode, parent *RBNode) {
var other *RBNode for (node == nil || rb_is_black(node)) && node != root.node {
// node是父节点的左孩子
if parent.left == node {
other = parent.right
// Case 1: node的兄弟节点是红色的
if rb_is_red(other) {
rb_set_black(other)
rb_set_red(parent)
left_rotate(root, parent)
other = parent.right
}
// Case 2: node的兄弟w是黑色,且w的俩个孩子也都是黑色的
if (other.left == nil || rb_is_black(other.left)) && (other.right == nil || rb_is_black(other.right)) {
rb_set_red(other)
node = parent
parent = node.parent
} else {
// Case 3: node的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
if other.right == nil || rb_is_black(other.right) {
rb_set_black(other.left)
rb_set_red(other)
right_rotate(root, other)
other = parent.right
}
// Case 4: node的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
other.color = parent.color
rb_set_black(parent)
rb_set_black(other.right)
left_rotate(root, parent)
node = root.node
break
}
} else {
other = parent.left
// Case 1: node的兄弟w是红色的
if rb_is_red(other) {
rb_set_black(other)
rb_set_red(parent)
right_rotate(root, parent)
other = parent.left
}
// Case 2: node的兄弟w是黑色,且w的俩个孩子也都是黑色的
if (other.left == nil || rb_is_black(other.left)) && (other.right == nil || rb_is_black(other.right)) {
rb_set_red(other)
node = parent
parent = node.parent
} else {
// Case 3: node的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
if other.left == nil || rb_is_black(other.left) {
rb_set_black(other.right)
rb_set_red(other)
left_rotate(root, other)
other = parent.left
}
// Case 4: node的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
other.color = parent.color
rb_set_black(parent)
rb_set_black(other.left)
right_rotate(root, parent)
node = root.node
break
}
}
} if node != nil {
rb_set_black(node)
}
} func main() {
//var datas = []Type{10, 40, 30, 60, 90, 70, 20, 50, 80}
var datas = []Type{10, 40, 30, 60, 90, 70, 20, 80} var root *RBRoot = new(RBRoot)
for _, data := range datas {
var node = &RBNode{key:data}
Add(root, node)
}
fmt.Print("前序遍历:")
PreTraverse(root.node)
fmt.Print("\n中序遍历:")
InTraverse(root.node)
fmt.Print("\n后序遍历:")
PostTraverse(root.node)
fmt.Print("\n\n") Print(root.node, root.node.key, 0)
fmt.Print("\n") var delNode = Find(root.node, 30)
Delete(root, delNode)
Print(root.node, root.node.key, 0)
fmt.Print("\n")
PrintRoute(root.node) }

(四)用go实现红黑树的更多相关文章

  1. Linux红黑树(二)——访问节点

    核心对红黑树使用两点说明 1.头文件 <Documentation/rbtree.txt> Linux's rbtree implementation lives in the file ...

  2. 红黑树(四)之 C++的实现

    概要 前面分别介绍红黑树的理论知识和红黑树的C语言实现.本章是红黑树的C++实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章. 目录1. 红黑树的介绍2. 红黑树的C++ ...

  3. 新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t

    新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csd ...

  4. 数据结构(四)--- 红黑树(RedBlock-Tree)

      文章图片来自邓俊辉老师课件 先提几个问题去思考学习本文 : 红黑树和2-4树(B-Tree)很像,那么它存在的动机又是什么呢 插入和删除操作的逻辑又是怎么样的,时间和空间复杂度可以达到怎么样 和 ...

  5. 菜鸟nginx源码剖析数据结构篇(四)红黑树ngx_rbtree_t[转]

    菜鸟nginx源码剖析数据结构篇(四)红黑树ngx_rbtree_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn ...

  6. 第十四章 红黑树——C++代码实现

    红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...

  7. 红黑树——算法导论(15)

    1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极 ...

  8. 算法设计和数据结构学习_5(BST&AVL&红黑树简单介绍)

    前言: 节主要是给出BST,AVL和红黑树的C++代码,方便自己以后的查阅,其代码依旧是data structures and algorithm analysis in c++ (second ed ...

  9. 数据结构中很常见的各种树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)

    数据结构中常见的树(BST二叉搜索树.AVL平衡二叉树.RBT红黑树.B-树.B+树.B*树) 二叉排序树.平衡树.红黑树 红黑树----第四篇:一步一图一代码,一定要让你真正彻底明白红黑树 --- ...

  10. 红黑树(二)之 C语言的实现

    概要 红黑树在日常的使用中比较常用,例如Java的TreeMap和TreeSet,C++的STL,以及Linux内核中都有用到.之前写过一篇文章专门介绍红黑树的理论知识,本文将给出红黑数的C语言的实现 ...

随机推荐

  1. C-03\浮点数转换与编码和补码

    工程生成文件格式了解(常用) 工具 文件 作用 vc++6.0 .dsw 最高级别的配置文件,记录了整个工作空间的配置信息,是一个纯文本的文件,创建新项目时自动生成 vc++6.0 .dsp 配置文件 ...

  2. Vue21 组件

    1 模块及组件简介 组件(component)是vue.js最强大的功能之一.组件的作用就是封装可重用的代码,通常一个组件就是一个功能体,便于在多个地方都能够调用这个功能体. 每个组件都是Vue的实例 ...

  3. 计算机网络基础06-Email应用

    1 构成组件 邮件客户端 邮件服务器 SMTP协议 Simple Mail Transfer Protocol 1.1 邮件客户端 读写Email消息 和服务器交互,收发消息 1.2 邮件服务器 邮箱 ...

  4. EF Core DBFirst和CodeFirst 模式使用方法

    一.安装依赖包 1.Microsoft.EntityFrameworkCore 2.Microsoft.EntityFrameworkCore.Tools 3.Microsoft.EntityFram ...

  5. WAVE音频文件格式及其64位扩展格式的简要介绍

    正文 关于 WAVE 文件格式,网上有不少介绍,但关于WAVE 64位扩展格式的介绍却是几乎没有. 所以本文的目的是简要介绍标准的 WAVE 格式,以及两种主要的扩展格式. 文中所有代码都用C语言来描 ...

  6. js原型链污染详解

    前言 之前打某湖论剑,两道js的题,给我整懵逼了,发现以前都没对js做过多少研究,趁着被毒打了,先研究一波js原型链,未雨绸缪. 基础 protype 首先我们研究js原型链,得搞明白原型是什么,这里 ...

  7. FreeFileSync:开源的文件同步工具 | Linux 中国

    转载知乎: https://zhuanlan.zhihu.com/p/194778373

  8. STM32L4 Keil ST-Link 连接失败

    ST-LINK 连接失败的因素,以我个人的经历而言有两种:一个是驱动问题,一个是插线问题.连接正常的情况如下图所示,SWDIO 能显示你的设备信息: 注意使用 SW 端口,JTAG 端口导致无法识别设 ...

  9. PostgreSQL控制文件讲解及案例

    PostgreSQL控制文件内容: 主要分为是三部分,初始化静态信息.WAL及检查点的动态信息.一些配置信息. 我们可以用过pg_controldata命令直接读取PostgreSQL控制文件内容: ...

  10. 🤗 PEFT: 在低资源硬件上对十亿规模模型进行参数高效微调

    动机 基于 Transformers 架构的大型语言模型 (LLM),如 GPT.T5 和 BERT,已经在各种自然语言处理 (NLP) 任务中取得了最先进的结果.此外,还开始涉足其他领域,例如计算机 ...