链你一表,叉你一树

174 阅读1分钟

一、单向链表


js实现单向链表

class Node {
    constructor(element, next) {
        this.element = element;
        this.next = next;
    }
}

class LinkedList {
    constructor() {
        this.head = null;
        this.size = 0; // 链表长度
    }
    add(index, element) {
        // 如果只传了一个参数,统一成两个的形式
        if (arguments.length === 1) {
            element = index;
            index = this.size;
        }
        // 越界判断
        if (index < 0 || index > this.size) throw new Error('越界');

        // 第一个节点
        if (index === 0) {
            let head = this.head;
            this.head = new Node(element, head);
            // 不是第一个节点,修改next指针
        } else {
            let prevNode = this._node(index - 1); // 找前一个节点,索引是size-1
            prevNode.next = new Node(element, prevNode.next);
        }

        this.size++;
    }
    remove(index) {
        let removeNode;
        // 只有一个的情况,删除的是头
        if (index === 0) {
            removeNode = this.head;
            if (removeNode) {
                this.head = this.head.next;
                this.size--;
            }
            // 有多个,则把上一个的指针指向以上一个为基础的,下一个的下一个
        } else {
            let prevNode = this._node(index - 1);
            removeNode = prevNode.next;
            prevNode.next = prevNode.next.next;
            this.size--;
        }
        return removeNode;
    }
    // 查找节点
    _node(index) {
        let current = this.head;
        for (let i = 0; i < index; i++) {
            current = current.next;
        }
        return current;
    }
    get(index) {
        return this._node(index);
    }
    set(index, element) {
        let node = this._node(index);
        node.element = element;
        return node;
    }
    clear() {
        this.size = 0;
        this.head = null;
    }
}

let link = new LinkedList();
link.add(1);
link.add(2);
link.add(3);
console.dir(link, {depth: 100});

module.exports = LinkedList;

/*
LinkedList {
  head: Node {
    element: 1,
    next: Node { element: 2, next: Node { element: 3, next: null } }
  },
  size: 3
}
*/

1.单链表反转

1) 递归实现-两两反转

image.png

reverse() {
    function r(head) {
        // 空链表或者只有一个
        if (head == null || head.next == null) return head;
        // 从最后面开始反转
        let newHead = r(head.next);
        // 指针反转
        head.next.next = head;
        // 老头指针指向null
        head.next = null;
        // 返回新头
        return newHead;
    }
    this.head = r(this.head);
    return this.head;
}
2)循环遍历-新链表

image.png

reverseLoop() {
    let head = this.head;
    if (head == null || head.next == null) return head;
    let newHead = null;

    while(head !== null) {
        let temp = head.next; // 保存2
        head.next = newHead; // head.next = null
        newHead = head; // newHead = 1  1.next = null
        head = temp; // 老的头边成了2
    }
    this.head = newHead;
    return newHead;
}

二叉搜索树


class Node {
    constructor(element, parent) {
        this.element = element;
        this.parent = parent;
        this.left = null;
        this.right = null;
    }
}

class Tree {
    constructor() {
        this.root = null;
    }
    add(element) {
        if (!this.root) {
            return this.root = new Node(element, null);
        }
        let currentNode = this.root;
        let parent;
        let compare;
        // 遍历找到父节点,左右分开
        while(currentNode) {
            compare = currentNode.element < element;
            parent = currentNode;
            if (compare) {
                currentNode = currentNode.right;
            } else {
                currentNode = currentNode.left;
            }
        }
        // 绑定父节点和子节点
        let node = new Node(element, parent);
        if (compare) {
            parent.right = node;
        } else {
            parent.left = node;
        }
    }
}

let tree = new Tree();
[10, 8, 19, 6, 15, 22, 20].forEach(item => {
    tree.add(item);
})
console.dir(tree, { depth: 100 });

1.二叉树遍历

image.png

1)先序遍历
// 先序遍历
preOrderTraversal() {
    function traversal(node) {
        if (node === null) return;
        console.log(node.element);
        traversal(node.left);
        traversal(node.right);
    }
    traversal(this.root);
}
// tree.preOrderTraversal();
2)中序遍历
// 中序遍历
inOrderTraversal() {
    function traversal(node) {
        if (node === null) return;
        traversal(node.left);
        console.log(node.element);
        traversal(node.right);
    }
    traversal(this.root);
}
// tree.inOrderTraversal();
3)后序遍历
// 后序遍历
postOrderTraversal() {
    function traversal(node) {
        if (node === null) return;
        traversal(node.left);
        traversal(node.right);
        console.log(node.element);
    }
    traversal(this.root);
}
// tree.postOrderTraversal();
4) 层序遍历
levelOrderTraversal(cb) {
    let stack = [this.root];
    let index = 0;
    let currentNode;
    while (currentNode = stack[index++]) {
        cb(currentNode);
        if (currentNode.left) {
            stack.push(currentNode.left);
        }
        if (currentNode.right) {
            stack.push(currentNode.right);
        }
    }
}
// tree.levelOrderTraversal((node) => {
//     node = node.element + 1;
// })
5) 二叉树蛇形遍历

2.二叉树反转

reverse(cb) {
    let stack = [this.root];
    let index = 0;
    let currentNode;
    while (currentNode = stack[index++]) {
        cb && cb(currentNode);
        
        // 左节点和右节点反转
        let temp = currentNode.left;
        currentNode.left = currentNode.right;
        currentNode.right = temp;

        if (currentNode.left) {
            stack.push(currentNode.left);
        }
        if (currentNode.right) {
            stack.push(currentNode.right);
        }
    }
}

let tree = new Tree();
[10, 8, 19, 6, 15, 22, 20].forEach(item => {
    tree.add(item);
})
tree.reverse((node) => {
    console.log(node.element); // 10, 19, 8, 22, 15, 6, 20
})