Skip to content

Commit b730ff0

Browse files
committedApr 27, 2016
Linked List implementation
Signed-off-by: Tim Henderson <tim.tadh@gmail.com>
1 parent 5810fc7 commit b730ff0

File tree

4 files changed

+415
-24
lines changed

4 files changed

+415
-24
lines changed
 

‎linked/node.go

+207
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package linked
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
import (
9+
"github.com/timtadh/data-structures/errors"
10+
"github.com/timtadh/data-structures/list"
11+
"github.com/timtadh/data-structures/types"
12+
)
13+
14+
15+
// A doubly linked list node.
16+
type Node struct {
17+
Data types.Hashable
18+
Next, Prev *Node
19+
}
20+
21+
// Compares the Data of the node to the passed element.
22+
func (n *Node) Equals(b types.Equatable) bool {
23+
switch x := b.(type) {
24+
case *Node: return n.Data.Equals(x.Data)
25+
default: return n.Data.Equals(b)
26+
}
27+
}
28+
29+
// Compares the Data of the node to the passed element.
30+
func (n *Node) Less(b types.Sortable) bool {
31+
switch x := b.(type) {
32+
case *Node: return n.Data.Less(x.Data)
33+
default: return n.Data.Less(b)
34+
}
35+
}
36+
37+
// Hashes the Data of the node to the passed element.
38+
func (n *Node) Hash() int {
39+
return n.Data.Hash()
40+
}
41+
42+
43+
44+
// A doubly linked list. There is no synchronization.
45+
// The fields are publically accessible to allow for easy customization.
46+
type LinkedList struct {
47+
Length int
48+
Head *Node
49+
Tail *Node
50+
}
51+
52+
func New() *LinkedList {
53+
return &LinkedList{
54+
Length: 0,
55+
Head: nil,
56+
Tail: nil,
57+
}
58+
}
59+
60+
func (l *LinkedList) Size() int {
61+
return l.Length
62+
}
63+
64+
func (l *LinkedList) Items() (it types.KIterator) {
65+
cur := l.Head
66+
it = func() (item types.Hashable, _ types.KIterator) {
67+
if cur == nil {
68+
return nil, nil
69+
}
70+
item = cur.Data
71+
cur = cur.Next
72+
return item, it
73+
}
74+
return it
75+
}
76+
77+
func (l *LinkedList) Backwards() (it types.KIterator) {
78+
cur := l.Tail
79+
it = func() (item types.Hashable, _ types.KIterator) {
80+
if cur == nil {
81+
return nil, nil
82+
}
83+
item = cur.Data
84+
cur = cur.Prev
85+
return item, it
86+
}
87+
return it
88+
}
89+
90+
func (l *LinkedList) Has(item types.Hashable) bool {
91+
for x, next := l.Items()(); next != nil; x, next = next() {
92+
if x.Equals(item) {
93+
return true
94+
}
95+
}
96+
return false
97+
}
98+
99+
func (l *LinkedList) Push(item types.Hashable) (err error) {
100+
return l.EnqueBack(item)
101+
}
102+
103+
func (l *LinkedList) Pop() (item types.Hashable, err error) {
104+
return l.DequeBack()
105+
}
106+
107+
func (l *LinkedList) EnqueFront(item types.Hashable) (err error) {
108+
n := &Node{Data: item, Next: l.Head}
109+
if l.Head != nil {
110+
l.Head.Prev = n
111+
} else {
112+
l.Tail = n
113+
}
114+
l.Head = n
115+
l.Length++
116+
return nil
117+
}
118+
119+
func (l *LinkedList) EnqueBack(item types.Hashable) (err error) {
120+
n := &Node{Data: item, Prev: l.Tail}
121+
if l.Tail != nil {
122+
l.Tail.Next = n
123+
} else {
124+
l.Head = n
125+
}
126+
l.Tail = n
127+
l.Length++
128+
return nil
129+
}
130+
131+
func (l *LinkedList) DequeFront() (item types.Hashable, err error) {
132+
if l.Head == nil {
133+
return nil, errors.Errorf("List is empty")
134+
}
135+
item = l.Head.Data
136+
l.Head = l.Head.Next
137+
if l.Head != nil {
138+
l.Head.Prev = nil
139+
} else {
140+
l.Tail = nil
141+
}
142+
l.Length--
143+
return item, nil
144+
}
145+
146+
func (l *LinkedList) DequeBack() (item types.Hashable, err error) {
147+
if l.Tail == nil {
148+
return nil, errors.Errorf("List is empty")
149+
}
150+
item = l.Tail.Data
151+
l.Tail = l.Tail.Prev
152+
if l.Tail != nil {
153+
l.Tail.Next = nil
154+
} else {
155+
l.Head = nil
156+
}
157+
l.Length--
158+
return item, nil
159+
}
160+
161+
func (l *LinkedList) First() (item types.Hashable) {
162+
if l.Head == nil {
163+
return nil
164+
}
165+
return l.Head.Data
166+
}
167+
168+
func (l *LinkedList) Last() (item types.Hashable) {
169+
if l.Tail == nil {
170+
return nil
171+
}
172+
return l.Tail.Data
173+
}
174+
175+
// Can be compared to any types.IterableContainer
176+
func (l *LinkedList) Equals(b types.Equatable) bool {
177+
if o, ok := b.(types.IterableContainer); ok {
178+
return list.Equals(l, o)
179+
} else {
180+
return false
181+
}
182+
}
183+
184+
// Can be compared to any types.IterableContainer
185+
func (l *LinkedList) Less(b types.Sortable) bool {
186+
if o, ok := b.(types.IterableContainer); ok {
187+
return list.Less(l, o)
188+
} else {
189+
return false
190+
}
191+
}
192+
193+
func (l *LinkedList) Hash() int {
194+
return list.Hash(l)
195+
}
196+
197+
func (l *LinkedList) String() string {
198+
if l.Length <= 0 {
199+
return "{}"
200+
}
201+
items := make([]string, 0, l.Length)
202+
for item, next := l.Items()(); next != nil; item, next = next() {
203+
items = append(items, fmt.Sprintf("%v", item))
204+
}
205+
return "{" + strings.Join(items, ", ") + "}"
206+
}
207+

‎linked/node_test.go

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package linked
2+
3+
import "testing"
4+
5+
import (
6+
"encoding/binary"
7+
"encoding/hex"
8+
"math/rand"
9+
"os"
10+
)
11+
12+
import (
13+
"github.com/timtadh/data-structures/list"
14+
"github.com/timtadh/data-structures/types"
15+
)
16+
17+
func init() {
18+
if urandom, err := os.Open("/dev/urandom"); err != nil {
19+
panic(err)
20+
} else {
21+
seed := make([]byte, 8)
22+
if _, err := urandom.Read(seed); err == nil {
23+
rand.Seed(int64(binary.BigEndian.Uint64(seed)))
24+
}
25+
urandom.Close()
26+
}
27+
}
28+
29+
func randstr(length int) types.String {
30+
if urandom, err := os.Open("/dev/urandom"); err != nil {
31+
panic(err)
32+
} else {
33+
slice := make([]byte, length)
34+
if _, err := urandom.Read(slice); err != nil {
35+
panic(err)
36+
}
37+
urandom.Close()
38+
return types.String(slice)
39+
}
40+
panic("unreachable")
41+
}
42+
43+
func randhex(length int) types.String {
44+
if urandom, err := os.Open("/dev/urandom"); err != nil {
45+
panic(err)
46+
} else {
47+
slice := make([]byte, length/2)
48+
if _, err := urandom.Read(slice); err != nil {
49+
panic(err)
50+
}
51+
urandom.Close()
52+
return types.String(hex.EncodeToString(slice))
53+
}
54+
panic("unreachable")
55+
}
56+
57+
func TestEquals(t *testing.T) {
58+
al := list.New(10)
59+
ll := New()
60+
for i := 0; i < 10; i++ {
61+
ll.Push(randhex(4))
62+
al.Push(ll.Last())
63+
}
64+
if !ll.Equals(al) {
65+
t.Fatalf("ll != al, %v != %v", ll, al)
66+
}
67+
t.Logf("ll %v", ll)
68+
t.Logf("al %v", ll)
69+
}
70+
71+
func TestPushPopSize(t *testing.T) {
72+
al := list.New(10)
73+
ll := New()
74+
for i := 0; i < 10; i++ {
75+
ll.Push(randhex(4))
76+
al.Push(ll.Last())
77+
}
78+
if !ll.Equals(al) {
79+
t.Fatalf("ll != al, %v != %v", ll, al)
80+
}
81+
for i := 0; i < 10; i++ {
82+
llItem, err := ll.Pop()
83+
if err != nil {
84+
t.Fatal(err)
85+
}
86+
alItem, err := al.Pop()
87+
if err != nil {
88+
t.Fatal(err)
89+
}
90+
if !alItem.Equals(llItem) {
91+
t.Fatalf("llItem != alItem, %v != %v", llItem, alItem)
92+
}
93+
}
94+
if !ll.Equals(al) {
95+
t.Fatalf("ll != al, %v != %v", ll, al)
96+
}
97+
}
98+
99+
func TestFrontPushPopSize(t *testing.T) {
100+
al := list.New(10)
101+
ll := New()
102+
for i := 0; i < 10; i++ {
103+
ll.EnqueFront(randhex(4))
104+
al.Insert(0, ll.First())
105+
}
106+
if !ll.Equals(al) {
107+
t.Fatalf("ll != al, %v != %v", ll, al)
108+
}
109+
for i := 0; i < 10; i++ {
110+
llItem, err := ll.DequeFront()
111+
if err != nil {
112+
t.Fatal(err)
113+
}
114+
alItem, err := al.Get(0)
115+
if err != nil {
116+
t.Fatal(err)
117+
}
118+
err = al.Remove(0)
119+
if err != nil {
120+
t.Fatal(err)
121+
}
122+
if !alItem.Equals(llItem) {
123+
t.Fatalf("llItem != alItem, %v != %v", llItem, alItem)
124+
}
125+
}
126+
if !ll.Equals(al) {
127+
t.Fatalf("ll != al, %v != %v", ll, al)
128+
}
129+
}

‎list/array_list.go

+34-20
Original file line numberDiff line numberDiff line change
@@ -183,52 +183,52 @@ func (l *List) Has(item types.Hashable) (has bool) {
183183

184184
func (l *List) Equals(b types.Equatable) bool {
185185
if o, ok := b.(types.IterableContainer); ok {
186-
return l.equals(o)
186+
return Equals(l, o)
187187
} else {
188188
return false
189189
}
190190
}
191191

192-
func (l *List) equals(o types.IterableContainer) bool {
193-
if l.Size() != o.Size() {
192+
func Equals(a, b types.IterableContainer) bool {
193+
if a.Size() != b.Size() {
194194
return false
195195
}
196-
cs, si := l.Items()()
197-
co, oi := o.Items()()
198-
for si != nil || oi != nil {
199-
if !cs.Equals(co) {
196+
ca, ai := a.Items()()
197+
cb, bi := b.Items()()
198+
for ai != nil || bi != nil {
199+
if !ca.Equals(cb) {
200200
return false
201201
}
202-
cs, si = si()
203-
co, oi = oi()
202+
ca, ai = ai()
203+
cb, bi = bi()
204204
}
205205
return true
206206
}
207207

208208
func (l *List) Less(b types.Sortable) bool {
209209
if o, ok := b.(types.IterableContainer); ok {
210-
return l.less(o)
210+
return Less(l, o)
211211
} else {
212212
return false
213213
}
214214
}
215215

216-
func (l *List) less(o types.IterableContainer) bool {
217-
if l.Size() < o.Size() {
216+
func Less(a, b types.IterableContainer) bool {
217+
if a.Size() < b.Size() {
218218
return true
219-
} else if l.Size() > o.Size() {
219+
} else if a.Size() > b.Size() {
220220
return false
221221
}
222-
cs, si := l.Items()()
223-
co, oi := o.Items()()
224-
for si != nil || oi != nil {
225-
if cs.Less(co) {
222+
ca, ai := a.Items()()
223+
cb, bi := b.Items()()
224+
for ai != nil || bi != nil {
225+
if ca.Less(cb) {
226226
return true
227-
} else if !cs.Equals(co) {
227+
} else if !ca.Equals(cb) {
228228
return false
229229
}
230-
cs, si = si()
231-
co, oi = oi()
230+
ca, ai = ai()
231+
cb, bi = bi()
232232
}
233233
return false
234234
}
@@ -246,6 +246,16 @@ func (l *List) Hash() int {
246246
return int(h.Sum32())
247247
}
248248

249+
func Hash(a types.ListIterable) int {
250+
h := fnv.New32a()
251+
bs := make([]byte, 4)
252+
for item, next := a.Items()(); next != nil; item, next = next() {
253+
binary.LittleEndian.PutUint32(bs, uint32(item.Hash()))
254+
h.Write(bs)
255+
}
256+
return int(h.Sum32())
257+
}
258+
249259
func (l *List) Items() (it types.KIterator) {
250260
i := 0
251261
return func() (item types.Hashable, next types.KIterator) {
@@ -273,6 +283,10 @@ func (l *List) Set(i int, item types.Hashable) (err error) {
273283
return nil
274284
}
275285

286+
func (l *List) Push(item types.Hashable) error {
287+
return l.Append(item)
288+
}
289+
276290
func (l *List) Append(item types.Hashable) error {
277291
return l.Insert(len(l.list), item)
278292
}

‎types/types.go

+45-4
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,13 @@ type MultiMap interface {
8888
MultiMapOperable
8989
}
9090

91+
type ContainerOperable interface {
92+
Has(item Hashable) bool
93+
}
94+
9195
type ItemsOperable interface {
9296
Sized
93-
Has(item Hashable) bool
97+
ContainerOperable
9498
Item(item Hashable) (Hashable, error)
9599
Add(item Hashable) (err error)
96100
Delete(item Hashable) (err error)
@@ -112,14 +116,34 @@ type IterableContainer interface {
112116
Has(item Hashable) bool
113117
}
114118

119+
type StackOperable interface {
120+
Push(item Hashable) (err error)
121+
Pop() (item Hashable, err error)
122+
}
123+
124+
type DequeOperable interface {
125+
EnqueFront(item Hashable) (err error)
126+
EnqueBack(item Hashable) (err error)
127+
DequeFront() (item Hashable, err error)
128+
DequeBack() (item Hashable, err error)
129+
First() (item Hashable)
130+
Last() (item Hashable)
131+
}
132+
133+
type LinkedOperable interface {
134+
Sized
135+
ContainerOperable
136+
StackOperable
137+
DequeOperable
138+
}
139+
115140
type ListOperable interface {
116141
Sized
117-
Has(item Hashable) bool
142+
ContainerOperable
143+
Append(item Hashable) (err error)
118144
Get(i int) (item Hashable, err error)
119145
Set(i int, item Hashable) (err error)
120146
Insert(i int, item Hashable) (err error)
121-
Append(item Hashable) (err error)
122-
Pop() (item Hashable, err error)
123147
Remove(i int) (err error)
124148
}
125149

@@ -151,6 +175,23 @@ type HList interface {
151175
List
152176
}
153177

178+
type Stack interface {
179+
Sized
180+
ContainerOperable
181+
StackOperable
182+
}
183+
184+
type Deque interface {
185+
Sized
186+
ContainerOperable
187+
DequeOperable
188+
}
189+
190+
type Linked interface {
191+
LinkedOperable
192+
ListIterable
193+
}
194+
154195
type Tree interface {
155196
Root() TreeNode
156197
}

0 commit comments

Comments
 (0)
Please sign in to comment.