简体   繁体   中英

Single Linked List search in Python

I want to search a value/character in a linked list and return the number of times the value/character is in the linked list. Also would it be easier if I just used recursion instead of tail recursion?

class MyList():
    __slots__=('head','size')

class Empty():
    __slots__=()

class NonEmpty():
    __slots__=('data','next')

def mkMyList():
    lst = MyList()
    lst.head = mkEmpty()
    lst.size = 0
    return lst

def mkEmpty():
    return Empty()

def mkNonEmpty(data,lst):
    node = NonEmpty()
    node.data  = data
    node.next = lst
    return node

def count(l, value, c = 0):
    l = mkMyList()
    if l.head != value:
        l.head = l.head.next
    if l.head == value:
        return count(l.head.next, value, c + 1)
    if l.size == 0:
        return c

When I try to test it, I get this:

count(s,'s',c= 0)
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    count(s,'s',c= 0)
  File "C:\Users\Qasim\Desktop\Linked Lists.py", line 30, in count
    l.head = l.head.next
AttributeError: 'Empty' object has no attribute 'next'

\\

Rather than use recursion, I would use the iterator pattern. Here is one way to do it in the context of your problem:

class LinkedList(object):

    class Node(object):
        __slots__ = ('prev', 'next', 'value')

        def __init__(self, prev=None, next=None, value=None):
            self.prev = prev
            self.next = next
            self.value = value

    def __init__(self, iterable=[]):
        self.head = LinkedList.Node() # dummy node
        self.tail = self.head
        self.size = 0
        for item in iterable:
            self.append(item)

    def __iter__(self):
        current = self.head
        while True:
            if current.next is not None:
                current = current.next
                yield current.value
            else:
                raise StopIteration

    def append(self, value):
        self.tail.next = LinkedList.Node(prev=self.tail, value=value)
        self.tail = self.tail.next
        self.size += 1

    def pop(self):
        if self.size > 0:
            value = self.tail.value
            self.tail = self.tail.prev
            self.tail.next = None
            self.size -= 1
            return value
        else:
            raise IndexError('pop from empty list')

    def count(self, value):
        cumsum = 0
        for item in self:
            if item == value:
                cumsum += 1
        return cumsum

By my defining a Python special method __iter__ , one can sequentially access the elements of a LinkedList in the following manner:

l = LinkedList([1, 2, 3, 3, 3, 4, 5])
for value in l:
    print(value)

which then makes the desired method count straight-forward to implement.

Note that I have used the Python generator syntax to implement __iter__ , you can read about generators and the yield statement here .

Tracing your code:

 l = mkMyList() # => head = Empty()
 if l.head != value: # True since head is Empty()
     l.head = l.head.next # Empty does not have a ".next" attribute

This is what the Traceback is telling you.

EDIT: Two more things: (1) I'm not sure why count is even calling mkMyList when it seems your intent is to pass it the list, l, in the function args. (2) I'm guessing you want to put the size-check if statement at the top of this function:

if l.size == 0:
    return c

The issue I see is that the list in count is never initialized properly. In mkMyList() , the head element is set to and Empty , which has no next attribute. In count() , you only use mkMyList() . This means that l.head is an Empty , and there's no way it could have a next attribute. To fix this, I would recommend instantiating the list l using the given input.

With regards to the question about recursion: no, there is very little difference in terms of composing a tail recursive function versus a regularly recursive function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM