264 lines
5.4 KiB
Go
264 lines
5.4 KiB
Go
package main
|
|
|
|
type DllId int64
|
|
|
|
type DoubleLinkedList[T any] struct {
|
|
data map[DllId]T
|
|
nodes map[DllId]*DLLNode
|
|
FirstNode DllId
|
|
LastNode DllId
|
|
length int
|
|
lastGeneratedId DllId
|
|
}
|
|
|
|
func NewDLL[T any]() *DoubleLinkedList[T] {
|
|
return &DoubleLinkedList[T]{
|
|
make(map[DllId]T),
|
|
make(map[DllId]*DLLNode),
|
|
-1,
|
|
-1,
|
|
0,
|
|
-1,
|
|
}
|
|
}
|
|
|
|
type DLLNode struct {
|
|
Id DllId
|
|
NextId DllId
|
|
PreviousId DllId
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) IsEmpty() bool {
|
|
return l.length == 0
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) insertEmpty(data T) DllId {
|
|
newId := l.nextId()
|
|
node := standaloneNode(newId)
|
|
l.data[newId] = data
|
|
l.nodes[newId] = node
|
|
l.FirstNode = newId
|
|
l.LastNode = newId
|
|
l.length++
|
|
return newId
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) InsertBefore(id DllId, data T) (DllId, bool) {
|
|
if node, ok := l.nodes[id]; ok {
|
|
return l.insertBetween(l.previousNode(node), node, data)
|
|
} else {
|
|
return -1, false
|
|
}
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) InsertAfter(id DllId, data T) (DllId, bool) {
|
|
|
|
if node := l.nodes[id]; node.Id == id {
|
|
return l.insertBetween(node, l.nextNode(node), data)
|
|
}
|
|
|
|
return -1, false
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) InsertFirst(data T) DllId {
|
|
if l.IsEmpty() {
|
|
return l.insertEmpty(data)
|
|
}
|
|
newId := l.nextId()
|
|
node := standaloneNode(newId)
|
|
l.data[newId] = data
|
|
l.nodes[newId] = node
|
|
firstNode := l.nodes[l.FirstNode]
|
|
node.NextId = firstNode.Id
|
|
firstNode.PreviousId = newId
|
|
l.FirstNode = newId
|
|
l.length++
|
|
return newId
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) InsertLast(data T) DllId {
|
|
if l.IsEmpty() {
|
|
return l.insertEmpty(data)
|
|
}
|
|
newId := l.nextId()
|
|
node := standaloneNode(newId)
|
|
l.data[newId] = data
|
|
l.nodes[newId] = node
|
|
lastNode := l.nodes[l.LastNode]
|
|
node.PreviousId = lastNode.Id
|
|
lastNode.NextId = newId
|
|
l.LastNode = newId
|
|
l.length++
|
|
return newId
|
|
}
|
|
|
|
func standaloneNode(id DllId) *DLLNode {
|
|
return &DLLNode{id, -1, -1}
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) nextId() DllId {
|
|
l.lastGeneratedId++
|
|
return l.lastGeneratedId
|
|
}
|
|
|
|
func mapNodes[T, K any](l *DoubleLinkedList[T], fn func(T, *DLLNode) K) <-chan K {
|
|
ch := make(chan K)
|
|
go func() {
|
|
defer close(ch)
|
|
iterId := l.FirstNode
|
|
for iterId > -1 {
|
|
val := fn(l.data[iterId], l.nodes[iterId])
|
|
ch <- val
|
|
iterId = l.nodes[iterId].NextId
|
|
|
|
}
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) Iter() <-chan T {
|
|
return mapNodes(l, func(datum T, node *DLLNode) T { return datum })
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) IterIds() <-chan DllId {
|
|
return mapNodes(l, func(datum T, node *DLLNode) DllId { return node.Id })
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) IterNodes() <-chan *DLLNode {
|
|
return mapNodes(l, func(datum T, node *DLLNode) *DLLNode { return node })
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) IterIdsFromLast() <-chan DllId {
|
|
ch := make(chan DllId)
|
|
go func() {
|
|
defer close(ch)
|
|
iterId := l.LastNode
|
|
for iterId > -1 {
|
|
ch <- iterId
|
|
iterId = l.nodes[iterId].PreviousId
|
|
}
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) GetById(id DllId) (T, bool) {
|
|
if d, ok := l.data[id]; ok {
|
|
return d, ok
|
|
} else {
|
|
var empty T
|
|
return empty, false
|
|
}
|
|
//for iterId := range l.IterIds() {
|
|
// if iterId == id {
|
|
// return l.data[id], true
|
|
// }
|
|
//}
|
|
//var nilValue T
|
|
//return nilValue, false
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) Last() (T, bool) {
|
|
if l.IsEmpty() {
|
|
var empty T
|
|
return empty, false
|
|
}
|
|
return l.data[l.lastGeneratedId], true
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) LastId() (DllId, bool) {
|
|
if l.IsEmpty() {
|
|
return -1, false
|
|
}
|
|
return l.LastNode, true
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) FirstId() (DllId, bool) {
|
|
if l.IsEmpty() {
|
|
return -1, false
|
|
}
|
|
return l.FirstNode, true
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) NextId(id DllId) (DllId, bool) {
|
|
nextId := l.nodes[id].NextId
|
|
return nextId, nextId > -1
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) previousNode(node *DLLNode) *DLLNode {
|
|
if node.PreviousId != -1 {
|
|
return l.nodes[node.PreviousId]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) nextNode(node *DLLNode) *DLLNode {
|
|
if node.NextId != -1 {
|
|
return l.nodes[node.NextId]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) insertBetween(before *DLLNode, after *DLLNode, data T) (DllId, bool) {
|
|
if before == nil && after == nil {
|
|
return l.insertEmpty(data), true
|
|
}
|
|
if before == nil {
|
|
return l.InsertFirst(data), true
|
|
}
|
|
if after == nil {
|
|
return l.InsertLast(data), true
|
|
}
|
|
id := l.nextId()
|
|
node := standaloneNode(id)
|
|
l.data[id] = data
|
|
l.nodes[id] = node
|
|
node.PreviousId = before.Id
|
|
node.NextId = after.Id
|
|
before.NextId = id
|
|
after.PreviousId = id
|
|
|
|
l.length++
|
|
return id, true
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) GroupByInPlace(combineValues func(a, b T) (T, bool)) {
|
|
for node := l.nodes[l.FirstNode]; node.NextId > -1; node = l.nodes[node.NextId] {
|
|
|
|
if _, ok := combineValues(l.data[node.Id], l.data[node.NextId]); ok {
|
|
//l.InsertAfter(nodeId, combinedVal)
|
|
//toRemove = append(toRemove, nodeId)
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) FilterInPlace(predicate func(a T) bool) {
|
|
|
|
toRemove := make([]DllId, 0)
|
|
for node := range l.IterNodes() {
|
|
//node := l.nodes[nodeId]
|
|
if !predicate(l.data[node.Id]) {
|
|
toRemove = append(toRemove, node.Id)
|
|
}
|
|
}
|
|
for _, id := range toRemove {
|
|
l.RemoveById(id)
|
|
}
|
|
}
|
|
|
|
func (l *DoubleLinkedList[T]) RemoveById(id DllId) {
|
|
node := l.nodes[id]
|
|
|
|
if nextNode, nextOk := l.nodes[node.NextId]; nextOk {
|
|
nextNode.PreviousId = node.PreviousId
|
|
}
|
|
|
|
if prevNode, prevOk := l.nodes[node.PreviousId]; prevOk {
|
|
prevNode.NextId = node.NextId
|
|
}
|
|
delete(l.data, id)
|
|
delete(l.nodes, id)
|
|
l.length--
|
|
|
|
}
|