[Algorithoms] Linked List Data Structure in JavaScript

A linked list is a collection of items where each item points to the next one in the list. Because of this structure, linked lists are very slow when searching for an item at a particular index. An array, by comparison, has quick gets when searching for an index, but a linked list must start at the beginning, often called the "head", and loop through each item's next property until we arrive at the item. This makes gets in a linked list an operation that takes O(n) time.

While gets might be slow in a linked list, it's other operations, like push and delete come with some great benefits we will see in the lesson.

/**
 * Linked list
 * 
 * API:
 * push
 * pop
 * get
 * delete
 * isEmpty
 * print
 */

 function createNode(value) {
     return {
         value,
         next: null
     }
 }

 function createLinkedList() {
     return {
         head: null,
         tail: null,
         length: 0,
         push(value) {
             /**Key takeaway: 
              *  Assign new node to current tail's next value
              *  Then
              *  Reassign the tail to new node
              */
             // Create Node
            const node = createNode(value);

            // If this is the first one
            if (this.head === null) {
                this.head = node
                this.tail = node
                this.length++;
                return node;
            }

            // if there already has nodes
            this.tail.next = node;
            this.tail = node;
            this.length++;
            return node;
         },
         pop() {
             const node = this.tail;
             // if this is no node
             if (!this.head) {
                 return null;
             }

             // if there is one node
             if (this.head === this.tail) {
                 this.head = null;
                 this.tail = null;
                 return node;
             }

             let current = this.head;
             let penultimate = null;

             while (current) {
                const {next} = current;
                if (next && next == this.tail) {
                    penultimate = current;
                    break;
                }
                current = current.next;
             }
             penultimate.next = null;
             this.tail = penultimate;
             this.length--;
             return node;
         },
         get(index = 0) {
            // no node in the list, return null
            if (!this.head) {
                return null;
            }

            // if the index < 0 or > length - 1, out of range
            if (index < 0 || index > this.length - 1) {
                return null;
            }

            // if index = 0, then return the first
            if (index === 0) {
                return this.head;
            }

            let current = this.head;
            let i = 0;
            while (i < index) {
                i++;
                current = current.next;
            }

            return current;
         },
         delete(index = 0) {
             /**
              * Key takewawy:
              * If we delete tail, we need to reassign the tail
              */
            // no node in the list, return null
            if (!this.head) {
                return null;
            }

            // if the index < 0 or > length - 1, out of range
            if (index < 0 || index > this.length - 1) {
                return null;
            }

            // if index = 0, then return the first
            if (index === 0) {
                const node = this.head;
                this.head = node.next;
                this.length--;
                return node;
            }

            let i = 0;
            let current = this.head;
            let previous = null;

            while (i < index) {
                i++;
                previous = current;
                current = current.next;
            }

            const deleted = current;
            previous.next = deleted.next;

            // If we delete the tail, we need to reassign tail
            if (previous.next === null) {
                this.tail = previous;
            }

            this.length--;
            return deleted;
         },
         isEmpty() {
             return this.length === 0;
         },
         print() {
            /**Key takeway: 
             *  remember to assign next node to current 
             *  Move the while loop
             * */
            let nodes = [];

            if (!this.head) {
                return 'Empty list';
            }

            let current = this.head;
            while (current) {
                nodes.push(current.value);
                current = current.next;
            }
            
            return nodes.join(' => ');
         }
     };
 }

 module.exports = {createLinkedList}

test:

const {createLinkedList} = require('../src/linked-list');

describe('linked list', () => {
    test('push: should add node into array', () => {
        const l = createLinkedList();
        // linked list should be empty
        expect(l.isEmpty()).toBe(true);
        // push a new node
        l.push('a');
        expect(l.isEmpty()).toBe(false);
        expect(l.length).toEqual(1);
        expect(l.print()).toEqual('a');
        // push a second node
        l.push('b');
        expect(l.length).toEqual(2);
        expect(l.print()).toEqual('a => b');
    });

    test('pop: should remove the last node from the list', () => {
        const l = createLinkedList();
        l.push('a');
        l.push('b');
        l.push('c');
        expect(l.length).toEqual(3);
        const p = l.pop();
        expect(p.value).toEqual('c');
        expect(l.length).toEqual(2);
    });

    test('get: should return the node for the given index', () => {
        const l = createLinkedList();
        // empty list, return null
        expect(l.get(0)).toBeNull();
        l.push('a');
        l.push('b');
        l.push('c');
        expect(l.length).toEqual(3);
        // out of index, retur null
        expect(l.get(-1)).toBeNull();
        expect(l.get(4)).toBeNull();

        // return the head
        expect(l.get(0).value).toEqual('a');

        // index in range not head
        expect(l.get(2).value).toEqual('c');
    });

    test('delete: should delete the node from the given index', () => {
        const l = createLinkedList();
        // empty list, return null
        expect(l.delete(0)).toBeNull();
        l.push('a');
        l.push('b');
        l.push('c');
        expect(l.length).toEqual(3);
        // out of index, retur null
        expect(l.delete(-1)).toBeNull();
        expect(l.delete(4)).toBeNull();
        // return the head
        expect(l.delete(0).value).toEqual('a');
        expect(l.length).toEqual(2);
        // delete the tail, reassign the tail
        expect(l.delete(1).value).toEqual('c');
        expect(l.tail.value).toEqual('b');
    });
});

猜你喜欢

转载自www.cnblogs.com/Answer1215/p/10117286.html
今日推荐