# double-linked-circular-list

### 说明

双向循环链表

### 源码

<https://github.com/ddzy/ts-utility-plugins/tree/master/src/ddzy/utility/algorithm/double-linked-circular-list>

### 用法

{% code title="doubleLinkedCircularList.test.ts" %}

```typescript
import { DoubleLinkedCircularList } from "../../utility/algorithm/double-linked-circular-list";
import { ListNode } from "../../utility/algorithm/double-linked-circular-list/list-node";

// ? Double Linked Circular List
describe('DLCL', () => {
  test('dlcl1.handleGetHead should return the `head` of linked-list', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });

    const expected = [2, 5, 8, 3, 7, 19, 23, 14, 41];
    const head = dlcl1.handleGetHead();
    const tail = dlcl1.handleGetTail();

    // ? 正向遍历
    let current: ListNode<number> | null = head;
    let count: number = 0;
    while (current && current !== tail) {
      expect(current.value).toBe(expected[count]);

      count++;
      current = current.next;
    }
    if (current) {
      expect(current.value).toBe(expected[count]);
      // ? 重置
      current = tail;
      count = expected.length - 1;
    }

    // ? 反向遍历
    while (current && current !== head) {
      expect(current.value).toBe(expected[count]);

      count--;
      current = current.prev;
    }
    if (current) {
      expect(current.value).toBe(expected[count]);
    }
  });

  test('dlcl1.handleGetTail should return the `tail` of linked-list', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });

    const expected = [2, 5, 8, 3, 7, 19, 23, 14, 41];
    const tail = dlcl1.handleGetTail();
    const head = dlcl1.handleGetHead();

    let current: ListNode<number> | null = tail;
    let count: number = expected.length - 1;
    // ? 反向遍历
    while (current && current !== head) {
      expect(current.value).toBe(expected[count]);

      count--;
      current = current.prev;
    }
    if (current) {
      expect(current.value).toBe(expected[count]);

      // ? 重置
      count = 0;
      current = head;
    }

    // ? 正向遍历
    while (current && current !== tail) {
      expect(current.value).toBe(expected[count]);

      count++;
      current = current.next;
    }
    if (current) {
      expect(current.value).toBe(expected[count]);
    }
  });

  test('dlcl1.handleGetLength should return the length of linked-list', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });

    const expected_1 = 9;
    const expected_2 = 8;
    const expected_3 = 10;

    const result_1: number = dlcl1.handleGetLength();
    expect(result_1).toBe(expected_1);

    const result_2: number = dlcl1.handleRemove(41).handleGetLength();
    expect(result_2).toBe(expected_2);

    const result_3: number = dlcl1.handleAppend(41).handleAppend(100).handleGetLength();
    expect(result_3).toBe(expected_3);
  });

  test('dlcl1.handleAppend should add new node to the tail of the linked-list', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });

    const expected_length_1 = 9;
    const expected_value_1 = 41;
    const expected_length_2 = 10;
    const expected_value_2 = 100;
    const expected_length_3 = 11;
    const expected_value_3 = 200;

    const result_length_1: number = dlcl1.handleGetLength();
    const result_value_1: number = (dlcl1.handleGetTail() as ListNode<number>).value;
    expect(result_length_1).toBe(expected_length_1);
    expect(result_value_1).toBe(expected_value_1);

    const result_length_2: number = dlcl1.handleAppend(100).handleGetLength();
    const result_value_2: number = (dlcl1.handleGetTail() as ListNode<number>).value;
    expect(result_length_2).toBe(expected_length_2);
    expect(result_value_2).toBe(expected_value_2);

    const result_length_3: number = dlcl1.handleAppend(200).handleGetLength();
    const result_value_3: number = (dlcl1.handleGetTail() as ListNode<number>).value;
    expect(result_length_3).toBe(expected_length_3);
    expect(result_value_3).toBe(expected_value_3);
  });

  test('dlcl1.handlePrepend should add new node to the head of the linked-list', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });

    const expected_length_1 = 9;
    const expected_value_1 = 2;
    const expected_length_2 = 10;
    const expected_value_2 = 100;
    const expected_length_3 = 11;
    const expected_value_3 = 200;

    const result_length_1: number = dlcl1.handleGetLength();
    const result_value_1: number = (dlcl1.handleGetHead() as ListNode<number>).value;
    expect(result_length_1).toBe(expected_length_1);
    expect(result_value_1).toBe(expected_value_1);

    const result_length_2: number = dlcl1.handlePrepend(100).handleGetLength();
    const result_value_2: number = (dlcl1.handleGetHead() as ListNode<number>).value;
    expect(result_length_2).toBe(expected_length_2);
    expect(result_value_2).toBe(expected_value_2);

    const result_length_3: number = dlcl1.handlePrepend(200).handleGetLength();
    const result_value_3: number = (dlcl1.handleGetHead() as ListNode<number>).value;
    expect(result_length_3).toBe(expected_length_3);
    expect(result_value_3).toBe(expected_value_3);
  });

  test('dlcl1.handleInsertBefore should add new list-node to the front of the target node', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });

    const expected_length_1 = 10;
    const expected_value_1 = 100;
    const expected_length_2 = 11;
    const expected_value_2 = 200;

    // ? 头节点
    const result_length_1: number = dlcl1.handleInsertBefore(2, 100).handleGetLength();
    const result_value_1: number = (dlcl1.handleGetHead() as ListNode<number>).value;
    expect(result_length_1).toBe(expected_length_1);
    expect(result_value_1).toBe(expected_value_1);

    // ? 其它部位
    const result_length_2: number = dlcl1.handleInsertBefore(2, 200).handleGetLength();
    const result_value_2: number = ((dlcl1.handleGetHead() as ListNode<number>).next as ListNode<number>).value;
    expect(result_length_2).toBe(expected_length_2);
    expect(result_value_2).toBe(expected_value_2);
  });

  test("dlcl1.handleInsertAfter should add new list-node to the back of the target node", () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });

    const expected_length_1 = 10;
    const expected_value_1 = 100;
    const expected_length_2 = 11;
    const expected_value_2 = 200;

    // ? 尾部节点
    const result_length_1: number = dlcl1.handleInsertAfter(41, 100).handleGetLength();
    const result_value_1: number = (dlcl1.handleGetTail() as ListNode<number>).value;
    expect(result_length_1).toBe(expected_length_1);
    expect(result_value_1).toBe(expected_value_1);

    // ? 其它部位
    const result_length_2: number = dlcl1.handleInsertAfter(41, 200).handleGetLength();
    const result_value_2: number = ((dlcl1.handleGetTail() as ListNode<number>).prev as ListNode<number>).value;
    expect(result_length_2).toBe(expected_length_2);
    expect(result_value_2).toBe(expected_value_2);
  });

  test('dlcl1.handleRemove should remove special node from the linked-list', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });
    const received_value = 7;
    const expected_length = 8;
    const expected_value = false;

    const result_length: number = dlcl1.handleRemove(7).handleGetLength();
    expect(result_length).toBe(expected_length);

    let sign: boolean = false;
    dlcl1.handleTraversalWithForward((node) => {
      if (node.value === received_value) {
        sign = true;
      }
    });
    expect(sign).toBe(expected_value);
  });

  test('dlcl1.handleTraversalWithForward should traversal the linked-list forwardly', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });
    const expected = [2, 5, 8, 3, 7, 19, 23, 14, 41];
    let sign = false;
    let count = 0;

    dlcl1.handleTraversalWithForward((node) => {
      node.value !== expected[count] && (sign = true);
      count++;
    });

    expect(sign).toBeFalsy();
  });

  test('dlcl1.handleTraversalWithBackward should traversal the linked-list backwardly', () => {
    const dlcl1 = new DoubleLinkedCircularList<number>({
      nodes: [2, 5, 8, 3, 7, 19, 23, 14, 41],
    });
    const expected = [41, 14, 23, 19, 7, 3, 8, 5, 2];

    let sign = false;
    let count = 0;

    dlcl1.handleTraversalWithBackward((node) => {
      node.value !== expected[count] && (sign = true);
      count++;
    });

    expect(sign).toBeFalsy();
  });
});
```

{% endcode %}

### API

| Name                        | Type                                                  | Description  |
| --------------------------- | ----------------------------------------------------- | ------------ |
| handleGetHead               | () => ListNode \| null                                | 获取头节点        |
| handleGetTail               | () => ListNode \| null                                | 获取尾节点        |
| handleAppend                | (value: V) => DoubleLinkedCircularList\<V>            | 尾部追加节点       |
| handlePrepend               | (value: V) => DoubleLinkedCircularList\<V>            | 首部追加节点       |
| handleInsertBefore          | (target: V, value: V) => DoubleLinkedCircularList\<V> | 将目标节点插入至源节点前 |
| handleInsertAfter           | (target: V, value: V) => DoubleLinkedCircularList\<V> | 将目标节点插入至源节点后 |
| handleTraversalWithForward  | (callback: (node: ListNode\<V>) => void) => void      | 正向遍历双向循环链表   |
| handleTraversalWithBackward | (callback: (node: ListNode\<V>) => void) => void      | 反向遍历双向循环链表   |
| handleGetLength             | () => number                                          | 获取链表长度       |
| handleRemove                | (value: V) => DoubleLinkedCircularList                | 移除链表指定节点     |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ddzy.gitbook.io/ts-utility-plugins-docs/utility/untitled/double-linked-circular-list.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
