def test_is_palindrome(func, llist): ll = LinkedList() ll.generate_nodes(llist.value) result = func(ll) assert result is llist.expected, ( f"{func.__name__} with '{llist.value}' as input returned {result}, " f"but {llist.expected} expected")
def sum_lists_followup2(llist1, llist2): """ Algorithmic solution using base 10. :param llist1: First linked list. :param llist2: Second linked list. :return: Reversed sum of linked lists' reversed numbers. """ len_l1, len_l2 = len(llist1), len(llist2) if len_l1 > len_l2: for i in range(len_l1 - len_l2): llist2.add_to_beginning(Node(0)) else: for i in range(len_l2 - len_l1): llist1.add_to_beginning(Node(0)) power = len( llist1 ) - 1 # take any of two as we equalized length by filling with zeros the shorter list head1, head2 = llist1.head, llist2.head sum_ = 0 while head1 is not None and head2 is not None: sum_ = sum_ + head1.data * (10**power) + head2.data * (10**power) power -= 1 head1, head2 = head1.next_node, head2.next_node result_ll = LinkedList() result_ll.generate_nodes(int(n) for n in str(sum_)) return result_ll
def test_add_to_end_when_head_is_none(): llist = LinkedList() appended_node = Node("a") llist.add_to_end(appended_node) assert llist.head == appended_node, ( f"After appending node {appended_node} to empty list its head must change to " f"{appended_node}") assert llist.head.next_node is None, "Next node of head now should be None"
def test_add_to_beginning_when_head_is_none(): llist = LinkedList() inserted_node = Node("a") llist.add_to_beginning(inserted_node) assert llist.head == inserted_node, ( f"After inserting node {inserted_node} to empty list its head must change to " f"{inserted_node}") assert llist.head.next_node is None, "Next node of head now should be None"
def test_kth_to_the_last(func, llist): ll = LinkedList() ll.generate_nodes(llist.input_list) result = func(ll, llist.k) assert result == llist.expected, ( f"{func.__name__} with '{llist.input_list}-{llist.k}' as input returned {result}, " f"but {llist.expected} expected" )
def looped_llist(): ll = LinkedList() ll.generate_nodes("abcdefgh") loop_node = ll.head.next_node last = ll.head while last.next_node is not None: last = last.next_node last.next_node = loop_node # Append to last node loop node return ll, loop_node
def sum_lists_followup(llist1, llist2): """ Solution using type conversions. :param llist1: First linked list. :param llist2: Second linked list. :return: Reversed sum of linked lists' reversed numbers. """ first_num = int("".join(str(n) for n in list(llist1))) second_num = int("".join(str(n) for n in list(llist2))) sum_ = [int(s) for s in list(str(first_num + second_num))] sum_llist = LinkedList() sum_llist.generate_nodes(sum_) return sum_llist
def _prepare_llists_for_test(): """Prepare test data.""" ll1, ll2 = LinkedList(), LinkedList() ll1.generate_nodes("defg") ll2.generate_nodes("abc") ll2.head.next_node.next_node = ll1.head # intersect lists in the middle positive = [(ll1, ll2, ll1.head), (ll1, ll1, ll1.head)] neg_ll = LinkedList() neg_ll.generate_nodes("abc") negative = [(ll1, neg_ll, None), (ll2, neg_ll, None)] return positive + negative
def test_delete_middle_node(data_for_test): llist = LinkedList() llist.generate_nodes(data_for_test.begin_nodes) middle_node = Node(data_for_test.middle) llist.add_to_end(middle_node) llist.generate_nodes(data_for_test.end_nodes) delete_middle_node(middle_node) result = "".join(l.data for l in llist) assert result == data_for_test.expected, ( f"Linked list: {data_for_test.begin_nodes}, remove node: {data_for_test.middle}' as input" f" produced '{result}', but '{data_for_test.expected}' expected")
def sum_lists2(llist1, llist2): """ Algorithmic solution using divmod operation. :param llist1: First linked list. :param llist2: Second linked list. :return: Reversed sum of linked lists' reversed numbers. """ head1, head2 = llist1.head, llist2.head result_ll = LinkedList() remainder = 0 while head1 is not None or head2 is not None: result = remainder if head1 is not None: result += head1.data head1 = head1.next_node if head2 is not None: result += head2.data head2 = head2.next_node remainder, node_data = divmod(result, 10) result_ll.add_to_end(Node(node_data)) if remainder: result_ll.add_to_end(Node(remainder)) return result_ll
def do_partition(llist, partition): """ Partition linked list around provided pivot. This implementation collects all nodes that are less than a pivot, and builds new partitioned linked list. :param llist: Instance of `LinkedList`. :param partition: Value of pivot to partition linked lists' smaller values :return: Partitioned linked list. """ if llist.head is None: print("Cannot find in empty list") return llist less = more = None current = llist.head last_less = None # needed to remember the last Node of less before None while current is not None: remembered_next = current.next_node if current.data < partition: if less is None: less = Node(current.data) last_less = less else: less, less.next_node = current, less else: if more is None: more = Node(current.data) else: more, more.next_node = current, more current = remembered_next last_less.next_node = more partitioned = LinkedList() partitioned.head = less return partitioned
def test_get_loop_node_negative(): ll = LinkedList() ll.generate_nodes("abc") # No loop assert detect_loop_node(ll) is None, "None expected, because there's no loop in the linked list"
def llist_data(request): ll_data, expected = request.param ll = LinkedList() ll.generate_nodes(ll_data) return ll, expected
def test_raises_when_remove_from_empty_list(): with pytest.raises(ValueError) as err: LinkedList().remove_node("some-node") assert "List is empty!" in str( err), "Exception is expected about empty list"
def singly_llist(): llist = LinkedList() llist.generate_nodes("abc") return llist
def followup_data(request): ll1, ll2 = LinkedList(), LinkedList() ll1.generate_nodes(request.param.ll1) ll2.generate_nodes(request.param.ll2) return ll1, ll2, request.param.expected
def llist_data(request): ll = LinkedList() ll.generate_nodes(request.param.llist) return ll, request.param.pivot