contributed by <Howard Chen>
This function was used to calcaute the length of the list by traversing from head to the end whcih is NULL.
This function was implemented to return the last node of the list. Since this is a singly linked list, the last node was linked with NULL. We have to traverse until the end to get the last node.
This part of the code is responsible for partitioning the sublist into two smaller sublists (left
and right
). It iterates through each node in the sublist p
and adds it to either the left
or right
sublist based on its value compared to the pivot value. This partitioning step divide the list into smaller parts for sorting.
In below code segment, after partitioning the sublist into left
, pivot
, and right
sublists, the pointers begin and end are updated to reflect the boundaries of these sublists. Additionally, the pointers left
and right
are reset to NULL, and the loop counter i is incremented by 2 to move to the next level of sublists.
begin[i] = left
and end[i] = list_tail(&left)
: Set the beginning and ending nodes of the left sublist.begin[i + 1] = pivot
and end[i + 1] = pivot
: Set the beginning and ending nodes of the pivot sublist (which is essentially just the pivot node).begin[i + 2] = right
and end[i + 2] = list_tail(&right)
: Set the beginning and ending nodes of the right sublist.left = right = NULL
: Reset the left and right pointers to NULL to prepare for the next iteration.The main spriti of timsort is that it divides the data into smaller chunks called "runs" and then uses a combination of insertion sort and merge sort to sort these runs efficiently.
During the weekly test, Google sheet deteremined my answer for BBBB and CCCC were incorrect. However, the real answers of &a->next
and &b->next
meaning the same expression as what I filled as below. They're all aim to assign the address of a->next
and b->next
to tail
since tail
is a pointer that pointed to the address of head.
In the original timsort code, the cmp
funtion was comparing integer number. However, we need to modified to compare char*
in order to used timsort in lab0-c
Commit: Add support to return queue size
Commit: Complete basic functions for make test pass
We use perf
command to help analysis the performance and cache-miss of q_sort and timsort. In order to use the same data, we copy trace-15-perf.cmd
and modified the sort
command to timsort
We could find that by using timsort, we could have less cache miss and better performance. The outcome confirms that Timsort exhibits a characteristic advantageous for memory locality.
Because Timsort divides the input data into small blocks called "runs." These runs represent contiguous subsequences of the input data that are already partially sorted. By sorting small chunks of data at a time, Timsort improves memory locality because it increases the likelihood that the elements being accessed during sorting are stored close together in memory.
q_sort
timsort
hlist_node: This structure represents a node in a hash list.
next
: Points to the next node in the hash list.pprev
: Points to the pointer that points to this node. In other words, it points to the previous node's next
, which allows efficient removal of nodes from the list without traversing the list from the beginning.hlist_head
: This structure represents the head of a hash list.
first
: Points to the first node in the hash table.order_node
: This structure represents a node containing ordered information.
node
: An instance of the hlist_node
structure, allowing it to be part of a hash list.val
: Holds the value of the node.idx
: Holds the index of the node.The hlist_add_head
function is used to add a node to the head of a hash list.
The find
funtion is used to find the index of root from indorer list
dfs
left
subtree:
dfs
for the left subtree.right
subtree:
dfs
for the right subtree.pre_low + (idx - in_low)
:The expression is used to determine the range of elements in the preorder list that correspond to the left subtree of the current node being constructed.
pre_low
: Index of the root node in the preorder list.idx
: Index of the root node in the inorder list.in_low
: Starting index of the current range in the inorder list.in_low
to idx - 1
) belong to the left subtree of the current node.idx
) and the starting index of the current range in the inorder list (in_low
).idx - in_low
gives us the count of elements in the left subtree. Adding this count to the index of the root node in the preorder list (pre_low
) gives us the index of the first element of the left subtree in the preorder list.pre_high - (in_high - idx - 1)
Same as previous, this expression is aim for the right subtree.
in_high
) and the index of the root node (idx
), plus 1 to include the root node.pre_high
) gives us the index of the first element of the right subtree in the preorder list.node_add
This function add the node to the hash list and count the hash key using it's value and the list size.
buildTree
First of all, build a hash table for inorder list. Then dfs
is used to build the tree
The LRUCache and LRUNode structures are used together to implement a Least Recently Used (LRU) cache.
LRUCache
LRUCache
represents the main cache structure.capacity
: The maximum capacity of the cache.count
: The current number of elements in the cache.dhead
: The head of a doubly linked list used to maintain the order of elements based on their usage.hhead[]
: An array of hash lists used for quick lookup of elements by their key.LRUNode
LRUNode
represents a node in the cache.key
: The key associated with the node.value
: The value associated with the key.node
: An instance of hlist_node
used to link nodes within a hash list.link
: An instance of list_head
used to link nodes within the doubly linked list maintained by the LRUCache.Reference from marvin0102 figure to illustrate the relationship of LRUCache and LRUNode as above.
The lRUCacheFree
function is responsible for freeing the memory allocated for the LRUCache object and its associated LRUNodes. It iterates through the doubly linked list of LRUNodes, deletes each node from the list, frees the memory associated with it, and finally frees the memory occupied by the LRUCache object itself.
The lRUCacheGet
function is used to retrieve the value associated with a given key from the LRUCache object.
%
with the capacity of the LRUCache
.list_entry
.list_move
function to indicate that it was recently accessed and returns the value associated with the key.-1
indicating that the key was not found in the LRUCache.The lRUCachePut
function is used to insert a key-value pair into the LRUCache
.
%
with the capacity of the LRUCache and iterates through the hash list associated with the computed hash value to check if the key already exists in the cache.LRUNode
to the front of the doubly linked list to indicate that it was recently accessed.cache
pointer with the found LRUNode.LRUNode
associated with the least recently used key from the cache by moving it to the front of the doubly linked list and updating the hash list.LRUNode
to the specified value.sz % BITS_PER_LONG
calculates the remainder when sz
is divided by BITS_PER_LONG
. It determines if there are any remaining bits after dividing sz
into groups of BITS_PER_LONG
.
The result of this expression is used as a condition to check if there are any remaining bits in the last word. If there are remaining bits, the macro performs additional operations to handle the last word separately.
The __ffs
function efficiently finds the position of the first set (non-zero) bit in a 64-bit word. The function first checks if the lower 32 bits of the word are all zeros. This is done by bitwise AND operation with 0xffffffff, which isolates the lower 32 bits.
__clear_bit
function calculate the mask for the specific bit to be cleared using BIT_MASK(nr)
. This creates a bitmask with all bits set to 1 except for the bit at position nr
, which is set to 0. For the address, it calculates the address of the word (a group of bits) containing the bit to be cleared. This is done by adding the word index (determined by BIT_WORD(nr)
) to the base address addr
. In the end, it perform a bitwise AND operation between the value pointed to by p
and the complement of the mask (~mask
). This clears the bit at position nr
in the word.