agentsclimarketplace

Elementary data structures

Skill Arcadi4/nerdy/clrs/elementary-data-structures

Skills from famous (or infamous) computer science tomes - "PhD-level intelligence." | 让AI替你读烦人的大部头

Install
npx -y skills add Arcadi4/nerdy --skill elementary-data-structures

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when reasoning about elementary data structures, dynamic sets, arrays, matrices, stacks, queues, linked lists, sentinels, rooted trees, representation choices, invariants, locality, or pointer-based tradeoffs under practical engineering constraints.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

14.3 KB, as published. Nobody here has run it

Elementary Data Structures

Overview

Treat elementary data structures as representation contracts, not classroom containers. The core move is to name the operations, access pattern, ownership model, and boundary invariants before choosing arrays, lists, stacks, queues, or tree links.

Shared CLRS Conventions

Follow the parent clrs skill for mathematical formatting, formula-free headings, direct polished answers, and CLRS-wide answer style.

When to Use

  • A problem asks for arrays, matrices, stacks, queues, linked lists, sentinels, rooted trees, or left-child/right-sibling representation.
  • You need to implement or review a dynamic set with SEARCH, INSERT, DELETE, MINIMUM, MAXIMUM, SUCCESSOR, or PREDECESSOR-like operations.
  • A design hinges on contiguity, locality, pointer chasing, deletion by pointer, circular-buffer wraparound, sentinel nodes, or parent/child/sibling navigation.
  • A production discussion needs the lesson behind an undergraduate structure rather than a literal reimplementation.

Do not use this skill merely because code contains an array or list. Use ordinary language/library conventions unless representation choice, invariants, asymptotic behavior, or access patterns are central.

First Decision: What Contract Does the Structure Serve?

NeedPreferWhy
Random indexed access and dense storageContiguous array or vectorIndex arithmetic is constant time and cache-friendly
Append/pop at one endDynamic array or stack abstractionSimpler and more local than pointer nodes
FIFO bounded bufferCircular array queueConstant-time operations with fixed memory and explicit full/empty policy
Frequent middle splice with existing node handlesDoubly linked listPointer rewiring is constant time once the node is known
Search by key in an unordered small setArray or list if tiny; otherwise a real dictionaryElementary structures expose the cost; later chapters provide better dictionaries
Ordered enumeration from elementary structures onlySorted array/list if updates are rareMaintaining order shifts update cost somewhere
Variable-arity rooted treeChild vectors or left-child/right-siblingChoose by child iteration, random child access, memory, and parent navigation

Before choosing, ask:

  1. Which operations are required by API, and which are merely convenient?
  2. Does DELETE receive a key, an index, an iterator, or a direct node pointer?
  3. Is order semantic, insertion-order, sorted-by-key, or irrelevant?
  4. Are elements moved, copied, referenced, or owned by the structure?
  5. Is performance dominated by asymptotic cost, cache locality, allocation, or simplicity?

Dynamic-Set Operation Discipline

Dynamic-set APIs separate queries from modifying operations so the representation can be judged by the exact contract.

Operation familyAsk firstCommon elementary consequence
Search by keyIs the structure sorted, indexed, or unordered?Unsorted arrays/lists scan; sorted arrays can binary search; sorted lists still traverse
InsertMust relative order be preserved?Arrays may shift; head-list insertion is cheap but changes order
DeleteIs a direct object pointer available?Doubly linked lists delete by pointer; singly linked lists usually need predecessor search
Minimum/maximumIs sorted order maintained?Cheap only if representation keeps the extreme at an accessible boundary
Successor/predecessorIs there bidirectional navigation or searchable order?Singly linked lists do not support predecessor cheaply

Do not answer with a more advanced structure as if the elementary representation already solved the problem. It is fine to say: "This introductory lesson shows why this elementary representation is insufficient; in production use a library hash map, ordered map, deque, vector, or tree implementation once the contract requires it."

Arrays and Matrices: Contiguity Is the Lesson

An array is a contiguous block of equal-sized slots. The transferable insight is that representation determines address calculation, locality, and movement cost.

  • Constant-time indexed access comes from fixed element size and arithmetic on the base address.
  • Variable-sized objects are normally stored indirectly through fixed-size references; this buys indexing but adds pointer chasing.
  • Row-major and column-major matrix layouts encode a traversal preference. Match layout to the dominant loop order or library ABI.
  • Single-array matrices are usually more cache-friendly than arrays of row pointers; arrays of row pointers support ragged rows and separate allocation.
  • Blocked layouts trade simple indexing for locality on tiled algorithms and cache-sized working sets.

Industrial warning: asymptotic constant time does not mean equal cost. Scanning a contiguous array can beat a theoretically similar pointer traversal because allocation, cache misses, branch prediction, and prefetching matter.

Stacks and Queues: Boundary Invariants Are the Product

Stacks and queues are restricted dynamic sets: deletion policy is part of the type.

StructureInvariantReview hazards
Stacktop names the most recently pushed live element, or the empty boundaryUnderflow, overflow, stale array contents mistaken for membership
Circular queuehead names next dequeue; tail usually names next enqueue slotEmpty/full ambiguity, wraparound off-by-one, capacity mismatch
DequeBoth ends are legal insertion and deletion boundariesHead/tail updates must be symmetric and tested through wraparound

For circular queues, choose exactly one full/empty policy and state it in code comments or type invariants:

  1. Leave one slot empty, so usable capacity is one less than storage capacity.
  2. Store an explicit count, so all slots are usable.
  3. Store an explicit full flag, and update it on every enqueue/dequeue transition.

Never mix policies. Tests should fill to capacity, attempt one extra enqueue, drain to empty, attempt one extra dequeue, and cross the physical end of the array in both directions.

Linked Lists: Handles Beat Search Only If You Already Have Them

Linked lists teach that update cost and discovery cost are different.

VariantStrengthHidden cost
Singly linked, unsortedConstant-time head insertion and forward traversalDeleting an arbitrary node usually needs predecessor search
Doubly linked, unsortedConstant-time splice/delete when a node handle is knownExtra pointer, more mutation surfaces, poor locality
Sorted listBoundary extrema and ordered traversal are simpleInsertion/search still traverse unless extra indexing exists
Circular list with sentinelUniform boundary cases and simpler splice/delete codeExtra dummy node and a value that must not be treated as user data

Use the phrase "given a pointer to the element" precisely. In DELETE(S, x), the operation removes a known object, but a singly linked list still cannot generally unlink x in constant time from x alone, because the predecessor's next field must change. Separate these cases explicitly:

  • Delete by key: first search for the node and usually its predecessor.
  • Delete by node plus predecessor handle: constant-time pointer rewrite in a singly linked list.
  • Delete by node alone in a doubly linked list: constant-time splice using prev and next.
  • Delete by node alone in a singly linked list: not generally constant time; special "copy successor into this node" tricks fail for tails and break identity/handle semantics.

Many production bugs come from quoting the update bound while hiding the search or predecessor handle needed to make the bound true.

Sentinels are an engineering pattern: replace special-case boundary checks with a dummy object that satisfies the same pointer protocol. Use them when they simplify hot, error-prone pointer code; avoid them when many tiny lists make dummy-node memory or sentinel misuse costly.

Rooted Trees: Pick Links for Navigation, Not for the Picture

Tree representation is an API choice.

RepresentationUse whenAvoid or qualify when
Binary tree links: parent, left, rightEach node has at most two named childrenGeneral trees or child lists are needed
Fixed child pointer arrayBranching factor is small and boundedMost nodes have far fewer children than the bound
Child vector/list per nodeRandom child iteration and simple APIs matterPer-node allocation overhead dominates
Parent pointers onlyAlgorithms walk toward roots, as in disjoint-set forestsDownward traversal is needed
Left-child/right-siblingArbitrary child counts need fixed pointer budget and ordered sibling traversalFrequent random child access or very wide nodes need faster child indexing

Left-child/right-sibling stores the first child and next sibling, optionally plus parent. It gives linear-time child iteration in the number of children and fixed pointer fields per node. It does not give constant-time access to the kth child; it is a compact traversal representation, not a general replacement for child arrays.

One Industrial Example: Bounded Work Queue Review

When reviewing an array-backed bounded FIFO queue, write the contract first:

storage length: capacity + 1
usable capacity: capacity
empty: head == tail
full: next(tail) == head
enqueue: require not full; write at tail; advance tail
dequeue: require not empty; read at head; advance head
membership: only slots on the circular interval from head to tail are live

Then test the state machine, not just one happy path:

  1. Empty queue rejects dequeue.
  2. Enqueue exactly usable capacity items.
  3. One more enqueue rejects overflow.
  4. Dequeue some items, enqueue enough to wrap tail.
  5. Drain through wraparound and verify FIFO order.
  6. One more dequeue rejects underflow.

This example captures the chapter's deeper lesson: simple structures are safe only when boundary invariants are explicit and repeatedly exercised.

Invariant and Proof Recipes

  • Array representation: State the live range separately from allocated storage. Stale values outside the live range are not members.
  • Stack: Prove push/pop by showing how top moves the live prefix boundary by one slot.
  • Circular queue: Prove FIFO by tracking the circular interval from head to tail under the chosen full/empty policy.
  • Linked-list splice: Name the two neighboring nodes before mutation; after mutation, every forward link's reverse link must agree in a doubly linked list.
  • Sentinel list: Treat the sentinel as the permanent boundary object; prove no operation deletes it or returns it as a real element.
  • Left-child/right-sibling tree: Prove child iteration by following left-child once and then right-sibling until the sibling boundary.

RED Pressure Failures This Skill Prevents

Baseline failureRequired correction
Jumping from elementary arrays/lists directly to hash tables or red-black trees without extracting the introductory representation lessonExplain the operation/access-pattern mismatch first, then mention production library structures as alternatives
Calling an in-memory red-black tree "cache-friendly" because it is logarithmicSeparate asymptotic depth from locality; pointer-heavy trees often lose locality to arrays or B-tree-like layouts
Saying singly linked lists delete in constant time from a node pointer aloneDistinguish delete-by-key, delete-by-node-plus-predecessor, doubly linked delete-by-node, and invalid singly linked delete-by-node-alone claims
Treating circular queues as just modulo arithmeticState head/tail meanings and the full/empty policy before code
Describing sentinels as only a micro-optimizationEmphasize boundary-condition simplification and the risk of returning/deleting dummy nodes
Treating left-child/right-sibling as a binary-tree trick with free child accessState fixed pointer budget, sibling traversal cost, and parent-pointer tradeoff

Common Mistakes

MistakeCorrection
Choosing a linked list for "fast insertion" while search dominatesCount the cost to find the insertion or deletion position
Treating a node pointer as enough to unlink from a singly linked listRequire a predecessor handle, use a doubly linked list, or state the narrow unsafe successor-copy exception and its identity/tail limits
Maintaining sorted order without pricing updatesSorted arrays/lists move or traverse on insert/delete
Forgetting satellite dataDecide whether nodes own records, point to records, or carry payload directly
Confusing allocated slots with live elementsTrack live ranges, top, head, tail, or node reachability
Mixing zero-origin and one-origin formulasConvert all index arithmetic to the implementation language before coding
Using sentinels in public APIsHide sentinels behind iterators or methods so callers cannot persist or delete them
Assuming textbook pointer structures are production defaultsPrefer mature library containers unless the representation contract is special

Verification Pressure Tests

Use these to check future answers:

  1. Industrial dictionary: For millions of request IDs with membership, update, and occasional ordering, the answer should explain the introductory representation tradeoffs before recommending a production map or ordered container.
  2. Circular queue wraparound: The answer should name head/tail meanings, full/empty policy, usable capacity, and overflow/underflow tests.
  3. Singly linked deletion: The answer should reject arbitrary constant-time deletion unless the predecessor or a special handle protocol is available.
  4. Sentinel list: The answer should simplify splice/delete while warning that the sentinel is not a user element.
  5. Variable-arity tree: The answer should compare left-child/right-sibling against child vectors or arrays based on child iteration, kth-child access, memory, and parent traversal.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.