mirror of
https://github.com/TheAlgorithms/Ruby
synced 2024-12-27 21:58:57 +01:00
Merge pull request #84 from TheAlgorithms/improve-doubly-linked-list
[Data structures] Add circular linked list and improve singly/doubly linked list
This commit is contained in:
commit
bc96d1c4ea
5 changed files with 311 additions and 82 deletions
|
@ -11,8 +11,9 @@
|
|||
* [Postorder Traversal](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/binary_trees/postorder_traversal.rb)
|
||||
* [Preorder Traversal](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/binary_trees/preorder_traversal.rb)
|
||||
* Linked Lists
|
||||
* [Double List](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/linked_lists/double_list.rb)
|
||||
* [Single List](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/linked_lists/single_list.rb)
|
||||
* [Circular Linked List](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/linked_lists/circular_linked_list.rb)
|
||||
* [Doubly Linked List](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/linked_lists/doubly_linked_list.rb)
|
||||
* [Singly Linked List](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/linked_lists/singly_linked_list.rb)
|
||||
* Queues
|
||||
* [Queue](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/queues/queue.rb)
|
||||
* Stacks
|
||||
|
|
109
data_structures/linked_lists/circular_linked_list.rb
Normal file
109
data_structures/linked_lists/circular_linked_list.rb
Normal file
|
@ -0,0 +1,109 @@
|
|||
# Define a node for the list
|
||||
class Node
|
||||
attr_accessor :value, :next
|
||||
|
||||
def initialize(value)
|
||||
@value = value
|
||||
@next = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Class for circular linked list (last node points to the head node)
|
||||
class CircularList
|
||||
attr_reader :head
|
||||
|
||||
def initialize
|
||||
@head = nil
|
||||
end
|
||||
|
||||
def insert_tail(value)
|
||||
newNode = Node.new(value)
|
||||
if @head.nil?
|
||||
@head = newNode
|
||||
@head.next = @head
|
||||
else
|
||||
tempNode = @head
|
||||
tempNode = tempNode.next while tempNode.next != @head
|
||||
newNode.next = @head
|
||||
tempNode.next = newNode
|
||||
end
|
||||
end
|
||||
|
||||
def insert_head(value)
|
||||
newNode = Node.new(value)
|
||||
if @head.nil?
|
||||
@head = newNode
|
||||
@head.next = head
|
||||
else
|
||||
tempNode = @head
|
||||
tempNode = tempNode.next while tempNode.next != @head
|
||||
newNode.next = @head
|
||||
tempNode.next = newNode
|
||||
@head = newNode
|
||||
end
|
||||
end
|
||||
|
||||
def print_list
|
||||
print '['
|
||||
unless @head.nil?
|
||||
printNode = @head
|
||||
while printNode.next != @head
|
||||
print printNode.value.to_s
|
||||
print ', '
|
||||
printNode = printNode.next
|
||||
end
|
||||
print printNode.value
|
||||
end
|
||||
print ']'
|
||||
|
||||
puts(STDOUT.flush)
|
||||
end
|
||||
|
||||
def delete_head
|
||||
return if @head.nil?
|
||||
|
||||
if @head.next != @head
|
||||
newHead = @head.next
|
||||
tempNode = newHead
|
||||
tempNode = tempNode.next while tempNode.next != @head
|
||||
tempNode.next = newHead
|
||||
@head = newHead
|
||||
elsif !@head.nil? && (@head.next == @head)
|
||||
@head = nil
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tail
|
||||
return if @head.nil?
|
||||
|
||||
if @head.next != @head
|
||||
tempNode = @head
|
||||
tempNode = tempNode.next while tempNode.next.next != @head
|
||||
tempNode.next = @head
|
||||
elsif !@head.nil? && (@head.next == @head)
|
||||
@head = nil
|
||||
end
|
||||
end
|
||||
|
||||
def is_empty
|
||||
@head.nil?
|
||||
end
|
||||
end
|
||||
|
||||
obj = CircularList.new
|
||||
|
||||
obj.insert_tail(1)
|
||||
obj.insert_tail(2)
|
||||
obj.insert_tail(3)
|
||||
obj.insert_tail(4)
|
||||
obj.insert_tail(5)
|
||||
obj.print_list
|
||||
|
||||
obj.insert_head(6)
|
||||
obj.print_list
|
||||
|
||||
obj.delete_tail
|
||||
obj.print_list
|
||||
|
||||
obj.delete_head
|
||||
obj.print_list
|
|
@ -1,78 +0,0 @@
|
|||
# Define a node in the list
|
||||
class Node
|
||||
attr_accessor :value, :next, :prev
|
||||
|
||||
def initialize(value)
|
||||
@value = value
|
||||
@next = nil
|
||||
@prev = nil
|
||||
end
|
||||
end
|
||||
|
||||
# A Class for double linked lists (each element links to the next one, and to the previous one)
|
||||
class DoubleList
|
||||
include Enumerable
|
||||
attr_accessor :head, :tail
|
||||
|
||||
def initialize
|
||||
@head = nil
|
||||
@tail = nil
|
||||
end
|
||||
|
||||
def insert_tail(value)
|
||||
new_node = Node.new(value)
|
||||
if @head.nil?
|
||||
@head = new_node
|
||||
@tail = new_node
|
||||
else
|
||||
@tail.next = new_node
|
||||
new_node.prev = @tail
|
||||
@tail = new_node
|
||||
end
|
||||
end
|
||||
|
||||
def insert_head(value)
|
||||
new_node = Node.new(value)
|
||||
if @head.nil?
|
||||
@head = new_node
|
||||
@tail = new_node
|
||||
else
|
||||
new_node.next = @head
|
||||
@head.prev = new_node
|
||||
@head = new_node
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tail
|
||||
until @tail.nil?
|
||||
@tail = @tail.prev
|
||||
@tail.next = nil unless @tail.nil?
|
||||
end
|
||||
end
|
||||
|
||||
def delete_head
|
||||
until @head.nil?
|
||||
@head = @head.next
|
||||
@head.prev = nil unless @head.nil?
|
||||
end
|
||||
end
|
||||
|
||||
def each
|
||||
return if @head.nil?
|
||||
|
||||
current = @head
|
||||
until current.nil?
|
||||
yield current.value
|
||||
current = current.next
|
||||
end
|
||||
end
|
||||
|
||||
def print_list
|
||||
# the to_a method is from Enumerable, will call each to get the values, and return an array
|
||||
puts '[' + to_a.join(', ') + ']'
|
||||
end
|
||||
|
||||
def empty?
|
||||
@head.nil?
|
||||
end
|
||||
end
|
179
data_structures/linked_lists/doubly_linked_list.rb
Normal file
179
data_structures/linked_lists/doubly_linked_list.rb
Normal file
|
@ -0,0 +1,179 @@
|
|||
class DoublyLinkedList
|
||||
# Initialize the data structure here.
|
||||
attr_reader :head, :tail, :size
|
||||
|
||||
def initialize
|
||||
@head = nil
|
||||
@tail = nil
|
||||
@size = 0
|
||||
end
|
||||
|
||||
# Get the value of the index-th node in the linked list.
|
||||
# If the index is invalid, return -1.
|
||||
def get(index)
|
||||
return -1 if @head.nil?
|
||||
return -1 if index > @size - 1
|
||||
|
||||
if index < @size - index
|
||||
iter = @head
|
||||
cnt = 0
|
||||
until iter.nil?
|
||||
return iter.val if cnt == index
|
||||
|
||||
iter = iter.next
|
||||
cnt += 1
|
||||
end
|
||||
else
|
||||
iter = @tail
|
||||
cnt = @size - 1
|
||||
until iter.nil?
|
||||
return iter.val if cnt == index
|
||||
|
||||
iter = iter.prev
|
||||
cnt -= 1
|
||||
end
|
||||
end
|
||||
-1
|
||||
end
|
||||
|
||||
# Add a node of value val before the first element of the linked list.
|
||||
# After the insertion, the new node will be the first node of the linked list.
|
||||
def insert_head(val)
|
||||
node = Node.new(val, nil, @head)
|
||||
@tail = node unless @head
|
||||
@head.prev = node if @head
|
||||
@head = node
|
||||
@size += 1
|
||||
end
|
||||
|
||||
# Append a node of value val to the last element of the linked list.
|
||||
def insert_tail(val)
|
||||
return insert_head(val) unless @head
|
||||
|
||||
node = Node.new(val, @tail, nil)
|
||||
@tail.next = node
|
||||
@tail = node
|
||||
@size += 1
|
||||
end
|
||||
|
||||
# Add a node of value val before the index-th node in the linked list.
|
||||
# If index equals to the length of linked list, the node will be appended
|
||||
# to the end of linked list. If index is greater than the length, the node
|
||||
# will not be inserted.
|
||||
def add_at_index(index, val)
|
||||
case index
|
||||
when 0 then insert_head(val)
|
||||
when @size then insert_tail(val)
|
||||
when 1...@size
|
||||
if index < @size - index
|
||||
iter = @head
|
||||
cnt = 0
|
||||
until iter.nil?
|
||||
return insert(iter, Node.new(val)) if cnt == index - 1
|
||||
|
||||
iter = iter.next
|
||||
cnt += 1
|
||||
end
|
||||
else
|
||||
iter = @tail
|
||||
cnt = @size - 1
|
||||
until iter.nil?
|
||||
return insert(iter, Node.new(val)) if cnt == index - 1
|
||||
|
||||
iter = iter.prev
|
||||
cnt -= 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def insert(node, new_node)
|
||||
new_node.prev = node
|
||||
new_node.next = node.next
|
||||
node.next.prev = new_node
|
||||
node.next = new_node
|
||||
@size += 1
|
||||
end
|
||||
|
||||
# Delete the index-th node in the linked list, if the index is valid.
|
||||
def delete_at_index(index)
|
||||
case index
|
||||
when 0
|
||||
return unless @head
|
||||
return @head, @tail, @size = nil, nil, 0 if @size == 1
|
||||
|
||||
remove(@head)
|
||||
when @size - 1
|
||||
remove(@tail)
|
||||
when 1...@size - 1
|
||||
if index < @size - index
|
||||
iter = @head
|
||||
cnt = 0
|
||||
until iter.nil?
|
||||
return remove(iter) if cnt == index
|
||||
|
||||
iter = iter.next
|
||||
cnt += 1
|
||||
end
|
||||
else
|
||||
iter = @tail
|
||||
cnt = @size - 1
|
||||
until iter.nil?
|
||||
return remove(iter) if cnt == index
|
||||
|
||||
iter = iter.prev
|
||||
cnt -= 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def remove(node)
|
||||
if node == @head
|
||||
@head = @head.next
|
||||
@head.prev = nil
|
||||
elsif node == @tail
|
||||
@tail = tail.prev
|
||||
@tail.next = nil
|
||||
else
|
||||
node.prev.next = node.next
|
||||
node.next.prev = node.prev
|
||||
end
|
||||
@size -= 1
|
||||
end
|
||||
|
||||
def print_values(head = @head)
|
||||
print "#{head.val} --> "
|
||||
if head.next.nil?
|
||||
puts("nil\n")
|
||||
return
|
||||
else
|
||||
print_values(head.next)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Node
|
||||
attr_accessor :val, :prev, :next
|
||||
|
||||
def initialize(val = nil, prev = nil, next_ = nil)
|
||||
@val = val
|
||||
@prev = prev
|
||||
@next = next_
|
||||
end
|
||||
end
|
||||
|
||||
obj = DoublyLinkedList.new
|
||||
obj.get(1)
|
||||
|
||||
obj.insert_head(2)
|
||||
obj.print_values
|
||||
|
||||
obj.insert_tail(3)
|
||||
obj.print_values
|
||||
|
||||
obj.add_at_index(3, 5)
|
||||
obj.print_values
|
||||
|
||||
obj.delete_at_index(1)
|
||||
obj.print_values
|
|
@ -1,5 +1,6 @@
|
|||
# Define a node in the list
|
||||
class Node
|
||||
# Initialize the data structure here.
|
||||
attr_accessor :value, :next
|
||||
|
||||
def initialize(value)
|
||||
|
@ -9,8 +10,7 @@ class Node
|
|||
end
|
||||
|
||||
# A Class for single linked lists (each element links to the next one, but not to the previous one)
|
||||
|
||||
class SingleList
|
||||
class SinglyLinkedList
|
||||
include Enumerable
|
||||
attr_accessor :head
|
||||
|
||||
|
@ -74,3 +74,21 @@ class SingleList
|
|||
@head.nil?
|
||||
end
|
||||
end
|
||||
|
||||
obj = SinglyLinkedList.new
|
||||
|
||||
obj.insert_head(1)
|
||||
obj.insert_head(2)
|
||||
obj.insert_head(3)
|
||||
obj.insert_head(4)
|
||||
obj.insert_head(5)
|
||||
obj.print_list
|
||||
|
||||
obj.insert_tail(6)
|
||||
obj.print_list
|
||||
|
||||
obj.delete_head
|
||||
obj.print_list
|
||||
|
||||
obj.delete_tail
|
||||
obj.print_list
|
Loading…
Reference in a new issue