Home > Net >  Linked lists: Why isn't my recursive sublist checker working?
Linked lists: Why isn't my recursive sublist checker working?

Time:01-10

The idea is to find segments of the second linked list that are identical to the first linked list, and add whichever node directly follows to a list that will be returned. So, if my first linked list is
h -> e -> y -> None
and my second is
h -> e -> y -> d -> u -> d -> e -> None
my output should be [d].

I've verified that the linked lists have been created properly, but will just add their contents as comments to keep things simple:

def find_sublist(list_start_node, corpus_start_node, output=[]):
    if corpus_start_node is None:
        return output
    elif list_start_node is None:
        output.append(corpus_start_node.item)
        return find_sublist(myList.head, corpus_start_node)
    elif list_start_node.item is corpus_start_node.item:
        return find_sublist(list_start_node.next_node, corpus_start_node.next_node)
    else:
        return find_sublist(myList.head, corpus_start_node.next_node)

# myList: 3 -> 7 -> None
# myCorpus: 3 -> 7 -> 8 -> 2 -> 34 -> 77 -> 21 -> 3 -> 7 -> 9 -> 2 -> 34 -> 88 -> 9 -> None

print(find_sublist(myList.head, myCorpus.head))

The bottom print function prints an output list of [8], when I should be getting [8, 9]. Is there something obvious I'm overlooking?

CodePudding user response:

Your main issue is that you need to make two checks when you find the first value in the corpus that matches your target list. First you need to check if the rest of the target list matches. And second, you need to check the rest of the corpus for the whole main list. Unfortunately, you don't really want to use the same recursive function for both, or you'll match the end of the target list anywhere they appear (regardless of whether they follow the earlier parts). Maybe you could add a flag to stop that, but it would be conceptually simpler with a separate function.

def matcher(needle, haystack):
    if haystack is None:  # failure case #1, we've run out of haystack
        return None
    if needle is None:    # success case, return the next haystack item
        return haystack.item
    if needle.item != haystack.item:  # falure case #2, a mismatch
        return None
    return matcher(needle.next_node, haystack.next_node)  # recurse

def searcher(needle, haystack, results=None):
    if results is None:   # avoid using a mutable default argument
        results = []

    if haystack is None:  # base case, we've searched the whole haystack
        return results

    match = matcher(needle, haystack) # test current position in haystack
    if match is not None:
        results.append(match)

    return searcher(needle, haystack.next_node, results)  # recurse

Note that since both of these functions are tail recursive, you can easily turn them into loops, and if you want, nest the loops in a single function:

def iterative_search_and_match(needle, haystack):
    results = []
    while needle and haystack:  # search loop
        match_needle = needle
        match_haystack = haystack
        while match_needle and match_haystack:  # match loop
            if match_needle.item != match_haystack.item:
                break
            match_needle = match_needle.next_node
            match_haystack = match_haystack.next_node
        else:  # this doesn't run if the break was hit!
            if match_haystack:
                results.append(match_haystack.item)
        needle = needle.next_node
        haystack = haystack.next_node
    return results

CodePudding user response:

I translated your function and it seems to work as expected. Is it possible there is some problem with your linked list setup?

# Setup
start_corpus = None
for x in reversed([3, 7, 8, 2, 34, 77, 21,
                   3, 7, 9, 2, 34, 88, 9]):
    start_corpus = (x, start_corpus)

start_word = (3, (7, None))

##################

def find_sublist(word, corpus):
    if corpus is None:
        return
    elif word is None:
        yield corpus[0]
        yield from find_sublist(start_word, corpus)
    elif word[0] == corpus[0]:
        yield from find_sublist(word[1], corpus[1])
    else:
        yield from find_sublist(start_word, corpus[1])

print(list(find_sublist(start_word, start_corpus)))
# [8, 9]
  •  Tags:  
  • Related