From 00c4c1b451e9c77471dc90c9635798dc368e1d3b Mon Sep 17 00:00:00 2001 From: hlccd <56643462+hlccd@users.noreply.github.com> Date: Fri, 22 Oct 2021 19:08:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86=E9=93=BE=E8=A1=A8,?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E4=BF=AE=E6=94=B9=E4=BA=86=E4=B9=8B=E5=89=8D?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=B8=AD=E5=87=BA=E7=8E=B0=E7=9A=84=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- goSTL/data_structure/deque/deque.go | 20 +- goSTL/data_structure/deque/node.go | 2 +- goSTL/data_structure/list/list.go | 409 ++++++++++++++++++++++++++ goSTL/data_structure/list/node.go | 169 +++++++++++ goSTL/data_structure/vector/vector.go | 2 +- goSTL/utils/comparator/comparator.go | 30 +- 6 files changed, 619 insertions(+), 13 deletions(-) create mode 100644 goSTL/data_structure/list/list.go create mode 100644 goSTL/data_structure/list/node.go diff --git a/goSTL/data_structure/deque/deque.go b/goSTL/data_structure/deque/deque.go index e24121e..2db4fe3 100644 --- a/goSTL/data_structure/deque/deque.go +++ b/goSTL/data_structure/deque/deque.go @@ -66,7 +66,7 @@ func New() *deque { // 以deque双向队列容器做接收者 // 将deque双向队列容器中所承载的元素放入迭代器中 // 节点的冗余空间不释放 -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param nil //@return i *iterator.Iterator 新建的Iterator迭代器指针 func (d *deque) Iterator() (i *Iterator.Iterator) { @@ -87,7 +87,7 @@ func (d *deque) Iterator() (i *Iterator.Iterator) { // 返回该容器当前含有元素的数量 // 该长度并非实际占用空间数量 // 若容器为空则返回0 -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param nil //@return size uint64 容器中实际使用元素所占空间大小 func (d *deque) Size() (size uint64) { @@ -102,7 +102,7 @@ func (d *deque) Size() (size uint64) { // 以deque双向队列容器做接收者 // 将该容器中所承载的元素清空 // 将该容器的首尾指针均置nil,将size重置为0 -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param nil //@return nil func (d *deque) Clear() { @@ -125,7 +125,7 @@ func (d *deque) Clear() { // 如果不含有元素则说明为空,返回true // 如果容器不存在,返回true // 该判断过程通过size进行判断,为0则为true,否则为false -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param nil //@return b bool 该容器是空的吗? func (d *deque) Empty() (b bool) { @@ -140,7 +140,7 @@ func (d *deque) Empty() (b bool) { // 以deque双向队列向量容器做接收者 // 在容器首部插入元素 // 通过链表首节点进行添加 -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param e interface{} 待插入元素 //@return nil func (d *deque) PushFront(e interface{}) { @@ -163,7 +163,7 @@ func (d *deque) PushFront(e interface{}) { // 以deque双向队列向量容器做接收者 // 在容器尾部插入元素 // 通过链表尾节点进行添加 -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param e interface{} 待插入元素 //@return nil func (d *deque) PushBack(e interface{}) { @@ -186,7 +186,7 @@ func (d *deque) PushBack(e interface{}) { // 以deque双向队列容器做接收者 // 利用首节点进行弹出元素,可能存在首节点全部释放要进行首节点后移的情况 // 当元素全部删除后,释放全部空间,将首尾节点都设为nil -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param nil //@return nil func (d *deque) PopFront() { @@ -214,7 +214,7 @@ func (d *deque) PopFront() { // 以deque双向队列容器做接收者 // 利用尾节点进行弹出元素,可能存在尾节点全部释放要进行尾节点前移的情况 // 当元素全部删除后,释放全部空间,将首尾节点都设为nil -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param nil //@return nil func (d *deque) PopBack() { @@ -242,7 +242,7 @@ func (d *deque) PopBack() { // 以deque双向队列容器做接收者 // 返回该容器的第一个元素,利用首节点进行寻找 // 若该容器当前为空,则返回nil -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param nil //@return e interface{} 容器的第一个元素 func (d *deque) Front() (e interface{}) { @@ -257,7 +257,7 @@ func (d *deque) Front() (e interface{}) { // 以deque双向队列容器做接收者 // 返回该容器的最后一个元素,利用尾节点进行寻找 // 若该容器当前为空,则返回nil -//@return d *deque 接收者的deque指针 +//@receiver d *deque 接收者的deque指针 //@param nil //@return e interface{} 容器的最后一个元素 func (d *deque) Back() (e interface{}) { diff --git a/goSTL/data_structure/deque/node.go b/goSTL/data_structure/deque/node.go index 1fe3127..2d3f28a 100644 --- a/goSTL/data_structure/deque/node.go +++ b/goSTL/data_structure/deque/node.go @@ -23,7 +23,7 @@ type node struct { } //deque双向队列容器接口 -//存放了deque容器可使用的函数 +//存放了node结点容器可使用的函数 //对应函数介绍见下方 type noder interface { nextNode() (m *node) //返回下一个结点 diff --git a/goSTL/data_structure/list/list.go b/goSTL/data_structure/list/list.go new file mode 100644 index 0000000..1b0913a --- /dev/null +++ b/goSTL/data_structure/list/list.go @@ -0,0 +1,409 @@ +package list + +//@Title deque +//@Description +// list链表容器包 +// 链表将所有结点通过指针的方式串联起来,从而使得其整体保持一个线性状态 +// 对于链表的实现,其增删元素的过程只需要新建一个结点然后插入链表中即可 +// 增删结点需要同步修改其相邻的元素的前后指针以保证其整体是联通的 +// 可接纳不同类型的元素 +// 通过并发控制锁保证了在高并发过程中的数据一致性 + +import ( + "github.com/hlccd/goSTL/utils/comparator" + "github.com/hlccd/goSTL/utils/iterator" + "sync" +) + +//list链表结构体 +//包含链表的头尾节点指针 +//当增删结点时只需要找到对应位置进行操作即可 +//当一个节点进行增删时需要同步修改其临接结点的前后指针 +//结构体中记录整个链表的首尾指针,同时记录其当前已承载的元素 +//使用并发控制锁以保证数据一致性 +type list struct { + first *node //链表首节点指针 + last *node //链表尾节点指针 + size uint64 //当前存储的元素个数 + mutex sync.Mutex //并发控制锁 +} + +//list链表容器接口 +//存放了list容器可使用的函数 +//对应函数介绍见下方 + +type lister interface { + Iterator() (i *Iterator.Iterator) //创建一个包含链表中所有元素的迭代器并返回其指针 + Sort(Cmp ...comparator.Comparator) //将链表中所承载的所有元素进行排序 + Size() (size uint64) //返回链表所承载的元素个数 + Clear() //清空该链表 + Empty() (b bool) //判断该链表是否位空 + Insert(idx uint64, e interface{}) //向链表的idx位(下标从0开始)插入元素组e + Erase(idx uint64) //删除第idx位的元素(下标从0开始) + Get(idx uint64) (e interface{}) //获得下标为idx的元素 + Set(idx uint64, e interface{}) //在下标为idx的位置上放置元素e + IndexOf(e interface{}, Equ ...comparator.Equaler) (idx uint64) //返回和元素e相同的第一个下标 + SubList(begin, num uint64) (newList *list) //从begin开始复制最多num个元素以形成新的链表 +} + +//@title New +//@description +// 新建一个list链表容器并返回 +// 初始链表首尾节点为nil +// 初始size为0 +//@receiver nil +//@param nil +//@return l *list 新建的list指针 +func New() (l *list) { + return &list{ + first: nil, + last: nil, + size: 0, + mutex: sync.Mutex{}, + } +} + +//@title Iterator +//@description +// 以list链表容器做接收者 +// 将list链表容器中所承载的元素放入迭代器中 +//@receiver l *list 接收者的list指针 +//@param nil +//@return i *iterator.Iterator 新建的Iterator迭代器指针 +func (l *list) Iterator() (i *Iterator.Iterator) { + if l == nil { + l = New() + } + l.mutex.Lock() + //将所有元素复制出来放入迭代器中 + tmp := make([]interface{}, l.size, l.size) + for n, idx := l.first, uint64(0); n != nil && idx < l.size; n, idx = n.nextNode(), idx+1 { + tmp[idx] = n.value() + } + i = Iterator.New(&tmp) + l.mutex.Unlock() + return i +} + +//@title Sort +//@description +// 以list链表容器做接收者 +// 将list链表容器中所承载的元素利用比较器进行排序 +// 可以自行传入比较函数,否则将调用默认比较函数 +//@receiver l *list 接收者的list指针 +//@param Cmp ...comparator.Comparator 比较函数 +//@return nil +func (l *list) Sort(Cmp ...comparator.Comparator) { + if l == nil { + l = New() + } + l.mutex.Lock() + //将所有元素复制出来用于排序 + tmp := make([]interface{}, l.size, l.size) + for n, idx := l.first, uint64(0); n != nil && idx < l.size; n, idx = n.nextNode(), idx+1 { + tmp[idx] = n.value() + } + if len(Cmp) > 0 { + comparator.Sort(&tmp, Cmp[0]) + } else { + comparator.Sort(&tmp) + } + //将排序结果再放入链表中 + for n, idx := l.first, uint64(0); n != nil && idx < l.size; n, idx = n.nextNode(), idx+1 { + n.setValue(tmp[idx]) + } + l.mutex.Unlock() +} + +//@title Size +//@description +// 以list链表容器做接收者 +// 返回该容器当前含有元素的数量 +//@receiver l *list 接收者的list指针 +//@param nil +//@return num int 容器中所承载的元素数量 +func (l *list) Size() (size uint64) { + if l == nil { + l = New() + } + return l.size +} + +//@title Clear +//@description +// 以list链表容器做接收者 +// 将该容器中所承载的元素清空 +// 将该容器的首尾指针均置nil,将size重置为0 +//@receiver l *list 接收者的list指针 +//@param nil +//@return nil +func (l *list) Clear() { + if l == nil { + l = New() + } + l.mutex.Lock() + //销毁链表 + l.first = nil + l.last = nil + l.size = 0 + l.mutex.Unlock() +} + +//@title Empty +//@description +// 以list链表容器做接收者 +// 判断该list链表容器是否含有元素 +// 如果含有元素则不为空,返回false +// 如果不含有元素则说明为空,返回true +// 如果容器不存在,返回true +// 该判断过程通过size进行判断,为0则为true,否则为false +//@receiver l *list 接收者的list指针 +//@param nil +//@return b bool 该容器是空的吗? +func (l *list) Empty() (b bool) { + if l == nil { + l = New() + } + return l.size == 0 +} + +//@title Insert +//@description +// 以list链表容器做接收者 +// 通过链表的首尾结点进行元素插入 +// 插入的元素可以有很多个 +// 通过判断idx +//@receiver l *list 接收者的list指针 +//@param e interface{} 待插入元素 +//@return nil +func (l *list) Insert(idx uint64, e interface{}) { + if l == nil { + l = New() + } + l.mutex.Lock() + n := newNode(e) + if l.size == 0 { + //链表中原本无元素,新建链表 + l.first = n + l.last = n + } else { + //链表中存在元素 + if idx == 0 { + //插入头节点 + n.insertNext(l.first) + l.first = n + } else if idx >= l.size { + //插入尾节点 + l.last.insertNext(n) + l.last = n + } else { + //插入中间节点 + //根据插入的位置选择从前或从后寻找 + if idx < l.size/2 { + //从首节点开始遍历寻找 + m := l.first + for i := uint64(0); i < idx-1; i++ { + m = m.nextNode() + } + m.insertNext(n) + } else { + //从尾节点开始遍历寻找 + m := l.last + for i := l.size - 1; i > idx; i-- { + m = m.preNode() + } + m.insertPre(n) + } + } + } + l.size++ + l.mutex.Unlock() +} + +//@title Erase +//@description +// 以list链表容器做接收者 +// 先判断是否为首尾结点,如果是首尾结点,在删除后将设置新的首尾结点 +// 当链表所承载的元素全部删除后则销毁链表 +// 删除时通过idx与总元素数量选择从前或从后进行遍历以找到对应位置 +// 删除后,将该位置的前后结点连接起来,以保证链表不断裂 +//@receiver l *list 接收者的list指针 +//@param idx uint64 被删除结点的下标(从0开始) +//@return nil +func (l *list) Erase(idx uint64) { + if l == nil { + l = New() + } + l.mutex.Lock() + if l.size > 0 && idx < l.size { + //链表中存在元素,且要删除的点在范围内 + if idx == 0 { + //删除头节点 + l.first = l.first.next + } else if idx == l.size-1 { + //删除尾节点 + l.last = l.last.pre + } else { + //删除中间节点 + //根据删除的位置选择从前或从后寻找 + if idx < l.size/2 { + //从首节点开始遍历寻找 + m := l.first + for i := uint64(0); i < idx; i++ { + m = m.nextNode() + } + m.erase() + } else { + //从尾节点开始遍历寻找 + m := l.last + for i := l.size - 1; i > idx; i-- { + m = m.preNode() + } + m.erase() + } + } + l.size-- + if l.size == 0 { + //所有节点都被删除,销毁链表 + l.first = nil + l.last = nil + } + } + l.mutex.Unlock() +} + +//@title Get +//@description +// 以list链表容器做接收者 +// 获取第idx位结点所承载的元素,若不在链表范围内则返回nil +//@receiver l *list 接收者的list指针 +//@param idx uint64 被获取的结点位置(从0开始) +//@return e interface{} 获取的元素 +func (l *list) Get(idx uint64) (e interface{}) { + if l == nil { + l = New() + } + if idx >= l.size { + return nil + } + l.mutex.Lock() + if idx < l.size/2 { + //从首节点开始遍历寻找 + m := l.first + for i := uint64(0); i < idx; i++ { + m = m.nextNode() + } + e = m.value() + } else { + //从尾节点开始遍历寻找 + m := l.last + for i := l.size - 1; i > idx; i-- { + m = m.preNode() + } + e = m.value() + } + l.mutex.Unlock() + return e +} + +//@title Set +//@description +// 以list链表容器做接收者 +// 修改第idx为结点所承载的元素,超出范围则不修改 +//@receiver l *list 接收者的list指针 +//@param idx uint64 被修改的结点位置(从0开始) +//@param e interface{} 修改后当元素 +func (l *list) Set(idx uint64, e interface{}) { + if l == nil { + l = New() + } + if idx >= l.size { + return + } + l.mutex.Lock() + if idx < l.size/2 { + //从首节点开始遍历寻找 + m := l.first + for i := uint64(0); i < idx; i++ { + m = m.nextNode() + } + m.setValue(e) + } else { + //从尾节点开始遍历寻找 + m := l.last + for i := l.size - 1; i > idx; i-- { + m = m.preNode() + } + m.setValue(e) + } + l.mutex.Unlock() +} + +//@title IndexOf +//@description +// 以list链表容器做接收者 +// 返回与e相同的元素的首个位置 +// 可以自行传入用于判断相等的相等器进行处理 +// 遍历从头至尾,如果不存在则返回l.size +//@receiver l *list 接收者的list指针 +//@param e interface{} 要查找的元素 +//@param Equ ...comparator.Equaler 相等器 +//@param idx uint64 首下标 +func (l *list) IndexOf(e interface{}, Equ ...comparator.Equaler) (idx uint64) { + if l == nil { + l = New() + } + l.mutex.Lock() + var equ comparator.Equaler + if len(Equ) > 0 { + equ = Equ[0] + } else { + equ = comparator.GetEqual() + } + n := l.first + //从头寻找直到找到相等的两个元素即可返回 + for idx = 0; idx < l.size && n != nil; idx++ { + if equ(n.value(), e) { + break + } + n = n.nextNode() + } + l.mutex.Unlock() + return idx +} + +//@title SubList +//@description +// 以list链表容器做接收者 +// 以begin为起点(包含),最多复制num个元素进入新链表 +// 并返回新链表指针 +//@receiver l *list 接收者的list指针 +//@param begin uint64 复制起点 +//@param num uint64 复制个数上限 +//@param newList *list 新链表指针 +func (l *list) SubList(begin, num uint64) (newList *list) { + if l == nil { + l = New() + } + newList = New() + l.mutex.Lock() + if begin < l.size { + //起点在范围内,可以复制 + n := l.first + for i := uint64(0); i < begin; i++ { + n = n.nextNode() + } + m := newNode(n.value()) + newList.first = m + newList.size++ + for i := uint64(0); i < num-1 && i+begin < l.size-1; i++ { + n = n.nextNode() + m.insertNext(newNode(n.value())) + m = m.nextNode() + newList.size++ + } + newList.last = m + } + l.mutex.Unlock() + return newList +} diff --git a/goSTL/data_structure/list/node.go b/goSTL/data_structure/list/node.go new file mode 100644 index 0000000..50dbfed --- /dev/null +++ b/goSTL/data_structure/list/node.go @@ -0,0 +1,169 @@ +package list + +//@Title list +//@Description +// list链表容器包 +// 该部分包含了链表的节点 +// 链表的增删都通过节点的增删完成 +// 结点间可插入其前后节点,并同时将两结点建立连接 +// 增删之后会返回对应的首尾节点以辅助deque容器仍持有首尾节点 +// 为保证效率问题,设定了一定的冗余量,即每个节点设定2^10的空间以存放元素 + +//链表的node节点结构体 +//pre和next是该节点的前后两个节点的指针 +//用以保证链表整体是相连的 +type node struct { + data interface{} //结点所承载的元素 + pre *node //前结点指针 + next *node //后结点指针 +} + +//list链表容器接口 +//存放了node容器可使用的函数 +//对应函数介绍见下方 + +type noder interface { + preNode() (m *node) //返回前结点指针 + nextNode() (m *node) //返回后结点指针 + insertPre(pre *node) //在该结点前插入结点并建立连接 + insertNext(next *node) //在该结点后插入结点并建立连接 + erase() //删除该结点,并使该结点前后两结点建立连接 + value() (e interface{}) //返回该结点所承载的元素 + setValue(e interface{}) //修改该结点承载元素为e +} + +//@title newNode +//@description +// 新建一个结点并返回其指针 +// 初始首结点的前后结点指针都为nil +//@receiver nil +//@param nil +//@return n *node 新建的node指针 +func newNode(e interface{}) (n *node) { + return &node{ + data: e, + pre: nil, + next: nil, + } +} + +//@title preNode +//@description +// 以node结点做接收者 +// 返回该结点的前结点 +//@receiver n *node 接收者的node指针 +//@param nil +//@return pre *node 该结点的前结点指针 +func (n *node) preNode() (pre *node) { + if n == nil { + return + } + return n.pre +} + +//@title nextNode +//@description +// 以node结点做接收者 +// 返回该结点的后结点 +//@receiver n *node 接收者的node指针 +//@param nil +//@return next *node 该结点的后结点指针 +func (n *node) nextNode() (next *node) { + if n == nil { + return + } + return n.next +} + +//@title insertPre +//@description +// 以node结点做接收者 +// 对该结点插入前结点 +// 并建立前结点和该结点之间的连接 +//@receiver n *node 接收者的node指针 +//@param pre *node 该结点的前结点指针 +//@return nil +func (n *node) insertPre(pre *node) { + if n == nil || pre == nil { + return + } + pre.next = n + pre.pre = n.pre + if n.pre != nil { + n.pre.next = pre + } + n.pre = pre +} + +//@title insertNext +//@description +// 以node结点做接收者 +// 对该结点插入后结点 +// 并建立后结点和该结点之间的连接 +//@receiver n *node 接收者的node指针 +//@param next *node 该结点的后结点指针 +//@return nil +func (n *node) insertNext(next *node) { + if n == nil || next == nil { + return + } + next.pre = n + next.next = n.next + if n.next != nil { + n.next.pre = next + } + n.next = next +} + +//@title insertNext +//@description +// 以node结点做接收者 +// 销毁该结点 +// 同时建立该节点前后节点之间的连接 +//@receiver n *node 接收者的node指针 +//@param nil +//@return nil +func (n *node) erase() { + if n == nil { + return + } + if n.pre == nil && n.next == nil { + return + } else if n.pre == nil { + n.next.pre = nil + } else if n.next == nil { + n.pre.next = nil + } else { + n.pre.next = n.next + n.next.pre = n.pre + } + n = nil +} + +//@title value +//@description +// 以node结点做接收者 +// 返回该结点所要承载的元素 +//@receiver n *node 接收者的node指针 +//@param nil +//@return e interface{} 该节点所承载的元素e +func (n *node) value() (e interface{}) { + if n == nil { + return nil + } + return n.data +} + +//@title setValue +//@description +// 以node结点做接收者 +// 对该结点设置其承载的元素 +//@receiver n *node 接收者的node指针 +//@param e interface{} 该节点所要承载的元素e +//@return nil +func (n *node) setValue(e interface{}) { + if n == nil { + return + } + n.data = e +} diff --git a/goSTL/data_structure/vector/vector.go b/goSTL/data_structure/vector/vector.go index fcfda91..a32704c 100644 --- a/goSTL/data_structure/vector/vector.go +++ b/goSTL/data_structure/vector/vector.go @@ -106,7 +106,7 @@ func (v *vector) Iterator() (i *Iterator.Iterator) { // 对元素中剩余的部分进行排序 //@receiver v *vector 接受者vector的指针 //@param Cmp ...comparator.Comparator 比较函数 -//@return i *iterator.Iterator 新建的Iterator迭代器指针 +//@return nil func (v *vector) Sort(Cmp ...comparator.Comparator) { if v == nil { v = New() diff --git a/goSTL/utils/comparator/comparator.go b/goSTL/utils/comparator/comparator.go index 5aac92b..3b12a3d 100644 --- a/goSTL/utils/comparator/comparator.go +++ b/goSTL/utils/comparator/comparator.go @@ -16,6 +16,10 @@ package comparator type Comparator func(a, b interface{}) int +//比较器的特种——相等器 +//判断传入的两个元素是否相等 +type Equaler func(a, b interface{}) (B bool) + //@title GetCmp //@description // 传入一个数据并根据该数据类型返回一个对应的比较器 @@ -25,7 +29,7 @@ type Comparator func(a, b interface{}) int //@param e interface{} //@return cmp Comparator 该类型对应的默认比较器 func GetCmp(e interface{}) (cmp Comparator) { - if e==nil{ + if e == nil { return nil } switch e.(type) { @@ -63,6 +67,30 @@ func GetCmp(e interface{}) (cmp Comparator) { return nil } +//@title GetEqual +//@description +// 传入一个数据并根据该数据类型返回一个对应的比较器 +// 若该类型并非系统自带类型,则返回个空比较器 +// 若传入元素为nil则之间返回nil +//@receiver nil +//@param e interface{} +//@return cmp Comparator 该类型对应的默认比较器 +func GetEqual() (equ Equaler) { + return basicEqual +} + +//@title basicEqual +//@description +// 返回基本比较器 +// 即有且仅有判断量元素是否完全相等 +//@receiver a interface{} 待判断相等的第一个元素 +//@receiver b interface{} 待判断相等的第二个元素 +//@param nil +//@return B bool 这两个元素是否相等? +func basicEqual(a, b interface{}) (B bool) { + return a == b +} + //以下为系统自带类型的默认比较器 func boolCmp(a, b interface{}) int {