희생양 트리 - 우아한 폭력도 종류

이진 검색 트리로, 다음 가장 중요한 것은, 자신의 균형을 유지하는 방법은 균형을 유지하기 위해, 이진 검색 나무 팔선 재계있는 등 AVL 나무, 레드 - 블랙 트리, Treap 나무,보기 흉한 나무로, 하지만 원래의 목적은, 자신의 방법이있다 회전에 따라 , 다음 노드 사이의 관계를 변경합니다.

특히, 일부 이진 검색 트리 구현은 레드 - 블랙 트리와 같은, 아주 지루한, 추가 및 삭제 노드에 대한 다스의 경우 총 다룰 필요가 완성 디버그하고 평가 일이 어두운 시간이었다.

희생양 트리 충족 불균형이 그녀의 재건에 균형, 직접 폭력을 조정하는 방법을 찾을 수 없습니다 특이한 나무입니다.

재건

의 image.png

그들은 균형 여부를 확인하는 어떤 조건에 몰랐다하지만 트리의 서브 트리보다도, 그것은 분명 불균형이다. (예약 주문에) 큰 작은에서 배열 우리는 직접 하위 트리 트리 촬영 평평.

의 image.png

양쪽에 새로운 요소로 루트 요소의 중간 아이로했다. 그녀의 재건이 완료를 위해 그래서,이 양측이 아래로 처지로, 중간에서 픽업 할 것 같은 느낌이 든다. 이진의 재건 후 기본 이진 트리 가득 , 그리고 매우 효율적입니다.

의 image.png

그래서 희생양 나무는 나무가 균형을해야하는지 여부를 결정하는 방법이다. 매우 간단한 각 트리가 0.5 내지 1 사이의 범위에서 밸런스 계수 (α)를 취한다. 트리 * 알파의 노드의 총 수는 <어떤 점을 아이 트리를 요약하면, 불균형이다. 대부분의 그림 예를 들어 위의 일곱 하위 트리 노드의 총의 루트 노드 6, 왼쪽 아이가 5 ~ 6 하위 트리 루트, 다섯 개 노드의 총, 알파가 0.7, 0.7 7 * <5을 가정한다, 그래서 고르지입니다.

작은, 다음 더 까다로운 균형이 재건 될 것이다 번 이상하면 알파, 알파,의 값 알파 큰 정도 균형 트리가 감소 될 것이다, 재건의 수는 감소한다. 일반적으로, 알파는 비교적 완만 한 0.7을.

삽입

삽입 일반 바이너리 시작 차이는 해당 리프 노드에 값이 밸런스를 조정하기 시작합니다. 자기 삽입 노드의 경우 나무의 낮은 수준이 균형을 충족하지 않는 경우, 하위 트리의 모든 여전히 재건해야하므로 재건의 많은 의미가있다, 다시 조정, 완료 깊은 수준 하위 트리 후 조정에서 가. 따라서, 재건 재건의 필요성을 결정하기 위해 먼저 아래, 루트에서 시작해야한다. 필요하지 않은 모든 노드를 분석, 단지 우리 경과에 새로 삽입에 리프 노드에 루트 노드에서 경로를 확인해야합니다.

너무 오래 재구성의 발생이 반복적으로 아래로하지 않기 때문에 다수의의 삽입으로 최대 재구성 한 번 발생 .

삭제

관행의 많은 종류가 있습니다 삭제 :

  1. 각 노드를 삭제하는 여부 판단이 재건 될 필요가 위에서 아래를 실시한다.

  2. 각 실제로 삭제하지 않는 노드를 삭제는 그냥 검색에 참여하지 않습니다 표시합니다. 삭제 노드의 서브 트리의 비율은 직접 재구성 소정 값보다 큰 경우,이 비 알파 직접 수행 될 수 있으며, 그것을 자유롭게 우리에 의해 제어 될 수있다.

  3. 각 실제로 삭제하지 않는 노드를 삭제는 그냥 검색에 참여하지 않습니다 표시합니다. 삽입 트리거가 더 이상 재건을 균형 원인이없는 경우, 방법은 노드의 삭제 표시됩니다 재건에 참여하지 밖으로 이동합니다.

두 번째와 세 번째 방법은 아니다 매우 다른 방법이다 삭제 대기 , 어떤 방법의 특정 사용 할 것.

코드

단지 삽입을 구현, 삭제 추적합니다 전체.

트리 노드 구조
public class ScapegoatTreeNode<E> {
        // 以此节点为根的子树的总节点个数
        private int size = 1;
        private E value;
        private ScapegoatTreeNode<E> leftChild;
        private ScapegoatTreeNode<E> rightChild;
        ScapegoatTreeNode(E value) {
            this.value = value;
        }

        public int getSize() {
            return size;
        }

        public void setSize(int size) {
            this.size = size;
        }

        public E getValue() {
            return value;
        }

        public void setValue(E value) {
            this.value = value;
        }

        public ScapegoatTreeNode<E> getLeftChild() {
            return leftChild;
        }

        public void setLeftChild(ScapegoatTreeNode<E> leftChild) {
            this.leftChild = leftChild;
        }

        public ScapegoatTreeNode<E> getRightChild() {
            return rightChild;
        }

        public void setRightChild(ScapegoatTreeNode<E> rightChild) {
            this.rightChild = rightChild;
        }
    }
삽입
public class ScapegoatTree<E extends Comparable<E>> {

    private ScapegoatTreeNode<E> root;
    private static final double ALPHA_MAX = 1;
    private static final double ALPHA_MIN = 0.5;
    private double alpha = 0.7;

    private List<ScapegoatTreeNode<E>> insertPath = new ArrayList<>();

    public ScapegoatTree() {
    }

    public ScapegoatTree(double alpha) {
        if (alpha < 0.5) {
            alpha = 0.5;
        }
        if (alpha > 1) {
            alpha = 0.99;
        }
        this.alpha = alpha;
    }

    public void insert(E value) {
        ScapegoatTreeNode<E> node = new ScapegoatTreeNode<>(value);
        if (root == null) {
            root = new ScapegoatTreeNode<>(value);
        } else {
            boolean successfullyInsertion = insertValue(root, node);
            if (successfullyInsertion) {
                insertPath.forEach(node->node.size++);
                tryAdjust();
            }
            clearInsertPath();
        }
    }

    private boolean insertValue(ScapegoatTreeNode<E> parent, ScapegoatTreeNode<E> node) {
        if (parent == null || node == null) {
            return false;
        }
        insertPath.add(parent);
        int com = node.getValue().compareTo(parent.getValue());
        if (com < 0) {
            if (parent.getLeftChild() != null) {
                return insertValue(parent.getLeftChild(), node);
            } else {
                parent.setLeftChild(node);
                return true;
            }
        } else if (com > 0) {
            if (parent.getRightChild() != null) {
                return insertValue(parent.getRightChild(), node);
            } else {
                parent.setRightChild(node);
                return true;
            }
        }
        return false;
    }

    private void tryAdjust() {
        for (int i = 0; i < insertPath.size(); i++) {
            ScapegoatTreeNode<E> node = insertPath.get(i);
            int leftChildNodeCount = Optional.ofNullable(node.getLeftChild())
                    .map(left -> left.size)
                    .orElse(0);
            if (leftChildNodeCount > (int)(node.size * alpha) || leftChildNodeCount < (int)(node.size * (1 - alpha))) {
                rebuild(node, i == 0 ? null : insertPath.get(i - 1));
                return;
            }
        }
    }

    private void rebuild(ScapegoatTreeNode<E> root, ScapegoatTreeNode<E> parent) {
        List<E> elements = new ArrayList<>();
        inOrderTraversal(root, elements);

        ScapegoatTreeNode<E> newRoot = reBuildCore(elements,0, elements.size() - 1);
        if (parent == null) {
            this.root = newRoot;
        } else if (parent.getLeftChild() == root) {
            parent.setLeftChild(newRoot);
        } else {
            parent.setRightChild(newRoot);
        }
    }

    private void inOrderTraversal(ScapegoatTreeNode<E> root, List<E> elements) {
        if (root == null) {
            return;
        }
        inOrderTraversal(root.getLeftChild(), elements);
        elements.add(root.getValue());
        inOrderTraversal(root.getRightChild(), elements);
    }

    private ScapegoatTreeNode<E> reBuildCore(List<E> elements, int start, int end) {
        if (start > end) {
            return null;
        }
        int middle = (int)Math.ceil((start + end) / 2.0);
        if (middle >= elements.size()) {
            return null;
        }

        ScapegoatTreeNode<E> root = new ScapegoatTreeNode<>(elements.get(middle));
        root.size = end - start + 1;
        root.setLeftChild(reBuildCore(elements, start, middle - 1));
        root.setRightChild(reBuildCore(elements, middle + 1, end));
        return root;
    }

    private void clearInsertPath() {
        insertPath.clear();
    }
}

의 원래 시작 www.peihuan.net , 소스를 표시하시기 바랍니다

추천

출처www.cnblogs.com/peihuan/p/11523351.html