//min, max 값 적용
        private void buttonApply_Click(object sender, RoutedEventArgs e)
        {
            float min, max;
            NumericTreeViewItem parent = (treeView.SelectedItem as NumericTreeViewItem).owner;

            if (float.TryParse(textBoxMin.Text, out min) && float.TryParse(textBoxMax.Text, out max))
            {
                if (min > max)
                {
                    MessageBox.Show("최소값이 최대값보다 큽니다.");
                }

                else if ((parent != null) && (min < parent.min || max > parent.max))
                {
                    MessageBox.Show("상위 노드의 범위를 벗어납니다.");
                }

                else
                {
                    //적용
                    (treeView.SelectedItem as NumericTreeViewItem).UpdateInfo(min, max, (bool)checkBoxMin.IsChecked, (bool)checkBoxMax.IsChecked);
                    checkRange();   //적용 후에 범위 에러 체크
                }
            }
            else
            {
                MessageBox.Show("잘못된 값을 입력하셨습니다.");
            }
        }
        private void LoadNode(XmlNode parent, ItemCollection items, NumericTreeViewItem parentItem)
        {
            foreach (XmlNode child in parent)
            {
                if (child.NodeType == XmlNodeType.Element && child.Name == "node")
                {
                    string tmp = child.Attributes["range"].Value;

                    bool withMin = tmp.Substring(0, 1) == "[";
                    bool withMax = tmp.Substring(tmp.Length - 1, 1) == "]";

                    string tmp2     = tmp.Substring(1, tmp.Length - 2);
                    int    tmpIndex = tmp2.IndexOf('-');

                    float min, max;
                    float.TryParse(tmp2.Substring(0, tmpIndex), out min);
                    float.TryParse(tmp2.Substring(tmpIndex + 1), out max);

                    NumericTreeViewItem c = new NumericTreeViewItem(0, 0, parentItem);
                    c.UpdateInfo(min, max, withMin, withMax);

                    items.Add(c);

                    if (child.HasChildNodes)
                    {
                        LoadNode(child, c.Items, c);
                    }
                }
            }
        }
        //데이터 값에 따른 절반 나누기 recursive
        private void staticAdd(int height, NumericTreeViewItem root, bool isHybrid, bool isFloat = false)
        {
            float midValue = isFloat ? (root.min + root.max) / 2 : (int)((root.min + root.max) / 2);

            if (root.min != midValue)
            {
                root.Items.Add(new NumericTreeViewItem(0, 0, root)
                {
                    IsExpanded = true
                });
                root.Items.Add(new NumericTreeViewItem(0, 0, root)
                {
                    IsExpanded = true
                });

                (root.Items[0] as NumericTreeViewItem).UpdateInfo(root.min, midValue, root.includeMin, false);
                (root.Items[1] as NumericTreeViewItem).UpdateInfo(midValue, root.max, true, root.includeMax);

                root.IsExpanded = true;   //확장

                bool hasChild = true;     //hybrid method에서, 자식이 있는지 삭제되었는지

                if (isHybrid)
                {
                    //준식별자의 경우: 범위 내 값이 k개 미만인 값이 존재한다면 하위 노드 필요 없음
                    bool caseA = (dm.GetAttrList()[index] as Attr).type == Attr.attrType.qi && (root.Items[0] as NumericTreeViewItem).count < dm.k;
                    bool caseB = (dm.GetAttrList()[index] as Attr).type == Attr.attrType.qi && (root.Items[1] as NumericTreeViewItem).count < dm.k;


                    //범위 내 값이 0개인 값이 존재한다면 하위 노드 필요 없음
                    bool caseC = (root.Items[0] as NumericTreeViewItem).count == 0;
                    bool caseD = (root.Items[1] as NumericTreeViewItem).count == 0;


                    if (caseA || caseB || caseC || caseD)
                    {
                        root.Items.RemoveAt(1);
                        root.Items.RemoveAt(0);
                        hasChild = false;
                    }
                }

                if (hasChild && height > 0)
                {
                    staticAdd(height - 1, root.Items[0] as NumericTreeViewItem, isHybrid);
                    staticAdd(height - 1, root.Items[1] as NumericTreeViewItem, isHybrid);
                }
            }

            else
            {
                maxDepth = maxDepth > height ? maxDepth : height;       //perfect binary를 벗어나는 height를 저장
            }
        }
        //하위 노드 생성
        private void buttonAdd_Click(object sender, RoutedEventArgs e)
        {
            NumericTreeViewItem parent = (treeView.SelectedItem as NumericTreeViewItem);

            parent.Items.Add(new NumericTreeViewItem(parent.min, parent.max, parent)
            {
                IsExpanded = true
            });
            parent.IsExpanded = true; //확장
            checkRange();             //확장 후에 범위 에러 체크
        }
        //선택 노드 삭제
        private void buttonDelete_Click(object sender, RoutedEventArgs e)
        {
            if ((treeView.SelectedItem as NumericTreeViewItem).Items.Count == 0)
            {
                NumericTreeViewItem parent = (treeView.SelectedItem as NumericTreeViewItem).owner;

                parent.Items.Remove(treeView.SelectedItem);
                parent.IsSelected = true; //삭제 후에 부모 노드 선택
                checkRange();             //삭제 후에 범위 에러 체크
            }

            else
            {
                MessageBox.Show("먼저 모든 하위노드를 삭제 해야합니다.");
            }
        }
        //루트 라운딩
        private void roundRoot()
        {
            bool minIsZero = list.Min() == 0;
            bool maxIsZero = list.Max() == 0;

            int minDigit = minIsZero ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(list.Min()))) + 1;        //최소값의 자리수
            int maxDigit = maxIsZero ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(list.Max()))) + 1;        //최대값의 자리수


            NumericTreeViewItem root = treeView.Items[0] as NumericTreeViewItem;

            float tmpRootMin = minIsZero ? 0 : (float)Math.Pow(10, minDigit - 1);
            int   tmpMaxcoef = (int)(Math.Abs(list.Max()) / Math.Pow(10, maxDigit - 1)) + 1;
            float tmpRootMax = maxIsZero ? 0 : (float)(tmpMaxcoef * Math.Pow(10, maxDigit - 1));

            root.UpdateInfo(tmpRootMin, tmpRootMax, true, false);   //루트노드 업데이트

            //노드의 min, max 로드
            textBoxMin.Text = root.min.ToString();
            textBoxMax.Text = root.max.ToString();
        }
        //데이터 값에 따르고 분포를 고려하는 절반 나누기 recursive
        private void heuristicAdd(int height, NumericTreeViewItem root, bool isFloat = false)
        {
            float midValue = isFloat ? (root.min + root.max) / 2 : (int)((root.min + root.max) / 2);

            if (root.min != midValue)
            {
                root.Items.Add(new NumericTreeViewItem(0, 0, root)
                {
                    IsExpanded = true
                });
                root.Items.Add(new NumericTreeViewItem(0, 0, root)
                {
                    IsExpanded = true
                });


                (root.Items[0] as NumericTreeViewItem).UpdateInfo(root.min, midValue, root.includeMin, false);
                (root.Items[1] as NumericTreeViewItem).UpdateInfo(midValue, root.max, true, root.includeMax);

                //데이터 분포 체크
                float dif = ((float)(root.Items[0] as NumericTreeViewItem).count - (root.Items[1] as NumericTreeViewItem).count) / root.count;

                if (dif > 0.3)
                {
                    int coef = dif > 0.7 ? (dif > 0.8 ? 8 : 5) : (dif > 0.5 ? 4 : 3);

                    midValue = isFloat ? root.min + (root.max - root.min) / coef : (int)(root.min + (root.max - root.min) / coef);
                    (root.Items[0] as NumericTreeViewItem).UpdateInfo(root.min, midValue, root.includeMin, false);
                    (root.Items[1] as NumericTreeViewItem).UpdateInfo(midValue, root.max, true, root.includeMax);
                }

                else if (dif < -0.3)
                {
                    int coef = dif < -0.7 ? (dif < -0.8 ? 8 : 5) : (dif < -0.5 ? 4 : 3);

                    midValue = isFloat ? root.max - (root.max - root.min) / coef : (int)(root.max - (root.max - root.min) / coef);
                    (root.Items[0] as NumericTreeViewItem).UpdateInfo(root.min, midValue, root.includeMin, false);
                    (root.Items[1] as NumericTreeViewItem).UpdateInfo(midValue, root.max, true, root.includeMax);
                }

                root.IsExpanded = true;   //확장

                //준식별자의 경우: 범위 내 값이 k개 미만인 값이 존재한다면 하위 노드 필요 없음
                bool caseA = (dm.GetAttrList()[index] as Attr).type == Attr.attrType.qi && (root.Items[0] as NumericTreeViewItem).count < dm.k;
                bool caseB = (dm.GetAttrList()[index] as Attr).type == Attr.attrType.qi && (root.Items[1] as NumericTreeViewItem).count < dm.k;


                //범위 내 값이 0개인 값이 존재한다면 하위 노드 필요 없음
                bool caseC = (root.Items[0] as NumericTreeViewItem).count == 0;
                bool caseD = (root.Items[1] as NumericTreeViewItem).count == 0;


                if (caseA || caseB || caseC || caseD)
                {
                    root.Items.RemoveAt(1);
                    root.Items.RemoveAt(0);
                }

                else if (height > 0)
                {
                    heuristicAdd(height - 1, root.Items[0] as NumericTreeViewItem);
                    heuristicAdd(height - 1, root.Items[1] as NumericTreeViewItem);
                }
            }
        }
        //데이터 분포에 따른 절반 나누기 recursive
        private void dynamicAdd(int height, NumericTreeViewItem root, int firstIndex, int lastIndex)
        {
            root.Items.Add(new NumericTreeViewItem(0, 0, root)
            {
                IsExpanded = true
            });
            root.Items.Add(new NumericTreeViewItem(0, 0, root)
            {
                IsExpanded = true
            });

            int midIndex = (firstIndex + lastIndex) / 2;        //중간 인덱스

            //최소와 중간이 같은 경우, 중간 인덱스를 뒤로 옮긴다.
            if (root.min == list[midIndex])
            {
                for (int i = midIndex; i < lastIndex; ++i)
                {
                    if (list[i] > list[midIndex])
                    {
                        midIndex = i;
                        break;
                    }
                }
            }

            //최대와 중간이 같은 경우, 중간 인덱스를 뒤로 옮긴다.
            else if (root.max == list[midIndex])
            {
                for (int i = midIndex; i > firstIndex; --i)
                {
                    if (list[i] < list[midIndex])
                    {
                        midIndex = i;
                        break;
                    }
                }
            }

            (root.Items[0] as NumericTreeViewItem).UpdateInfo(root.min, list[midIndex], root.includeMin, false);
            (root.Items[1] as NumericTreeViewItem).UpdateInfo(list[midIndex], root.max, true, root.includeMax);

            root.IsExpanded = true;   //확장


            //준식별자의 경우: 범위 내 값이 k개 미만인 값이 존재한다면 하위 노드 필요 없음
            bool caseA = (dm.GetAttrList()[index] as Attr).type == Attr.attrType.qi && (root.Items[0] as NumericTreeViewItem).count < dm.k;
            bool caseB = (dm.GetAttrList()[index] as Attr).type == Attr.attrType.qi && (root.Items[1] as NumericTreeViewItem).count < dm.k;


            //범위 내 값이 0개인 값이 존재한다면 하위 노드 필요 없음
            bool caseC = (root.Items[0] as NumericTreeViewItem).count == 0;
            bool caseD = (root.Items[1] as NumericTreeViewItem).count == 0;


            if (caseA || caseB || caseC || caseD)
            {
                root.Items.RemoveAt(1);
                root.Items.RemoveAt(0);
            }

            else if (height > 0)
            {
                dynamicAdd(height - 1, root.Items[0] as NumericTreeViewItem, firstIndex, midIndex);
                dynamicAdd(height - 1, root.Items[1] as NumericTreeViewItem, midIndex, lastIndex);
            }
        }
            public string range;                       //xml 기록용

            public NumericTreeViewItem(float min = 0, float max = 0, NumericTreeViewItem owner = null)
            {
                UpdateInfo(min, max, true, true);
                IsSelected = true;
                this.owner = owner;
            }