Сортировка слиянием не работает должным образом в React - PullRequest
2 голосов
/ 01 августа 2020

Я отлаживал этот код часами, но не понял, в чем дело. items - это список элементов div с произвольной высотой. Может кто-нибудь мне помочь, я не могу найти, в чем проблема с этим кодом?

mergeSort1(l, r) {
    if (l < r) {
        let mid = Math.floor((l + r) / 2)
        this.mergeSort1(l, mid)
        this.mergeSort1(mid + 1, r)
        this.merge1(l, mid, r)
    }
}
merge1(l, mid, r) {
    let items = document.getElementsByClassName("item")
    items = Array.from(items)
    let left = items.slice(l, mid + 1)
    let right = items.slice(mid + 1, r + 1)
    let I = 0
    let J = 0
    let k = 0
    let t = []
    
    while (I < left.length && J < right.length) {
        if (parseInt(left[I].style.height) < parseInt(right[J].style.height)) {
            t.push(left[I].style.height)
            items[k + l].style.height = left[I].style.height
            I = I + 1
            k++
        } else {
            items[k + l].style.height = right[J].style.height
            t.push(right[J].style.height)
            J = J + 1
            k++
        }
    }
    while (I < left.length) {
        items[k + l].style.height = left[I].style.height
        k++
        t.push(left[I].style.height)
        I = I + 1
    }
    while (J < right.length) {
        items[k + l].style.height = right[J].style.height
        t.push(right[J].style.height)
        J = J + 1
        k++
    }
    console.log(t)
}
this.mergeSort1(0, this.state.arr.length - 1)

arr инициализировано в componentDidMount():

componentDidMount() {
    //this.step(this)
    
    var a = []
    for (var i = 0; i < 200; i++) {
        a.push(Math.round(Math.random() * 80))
    }
    this.setState({
        arr : a
    }, () => console.log(this.state.arr))
}

In render Метод:

arr.map((h, i) => {
        return (
            <div className="item" key={i} style={{height:h+'vh'}}>
            </div>)
   })

Ввод:

arr = [ 52, 68, 34, 60, 60, 42, 72, 70, 76, 52, 53, 51, 62, 47, 73, 44, 30, 0, 27, 25, 45, 40, 39, 12, 33, 33, 41, 74, 10, 30, 48, 17, 21, 7, 29, 33, 32, 56, 79, 29, 36, 16, 79, 68, 44, 37, 34, 36, 4, 35, 59, 54, 2, 11, 56, 78, 25, 16, 9, 69, 39, 80, 48, 5, 34, 68, 68, 21, 48, 42, 75, 57, 8, 76, 20, 76, 59, 50, 3, 52, 13, 7, 19, 6, 20, 72, 76, 46, 23, 10, 43, 16, 50, 16, 15, 58, 63, 53, 11, 52, …]

Выход (логарифм высот div после mergeSort):

["0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "0vh", "1vh", "1vh", "1vh", "35vh", "35vh", "66vh", "70vh"]

1 Ответ

0 голосов
/ 02 августа 2020

Проблема в том, что вы пытаетесь отсортировать массив элементов DOM по высоте, изменяя высоту, установленную в их стиле. Это вызывает две проблемы:

  1. Array.from и items.slice создают новые массивы, но не создают копии содержащихся в них элементов DOM. Поэтому, когда вы назначаете высоту элемента, вы меняете высоту элемента в другом месте в items. Это может быть элемент, который еще предстоит отсортировать.
  2. Вы используете React. Вы должны позволить React контролировать DOM: вы указываете своим компонентам, как отрисовывать себя в определенном состоянии, и позволяете React выяснять, как изменить DOM. числа в this.state.arr, тогда ваш код работает. В методе merge1 избавьтесь от массива items, замените любую ссылку на items на this.state.arr и удалите все использования .style.height и parseInt:
    merge1(l, mid, r) {
        let left = this.state.arr.slice(l, mid + 1)
        let right = this.state.arr.slice(mid + 1, r + 1)
        let I = 0
        let J = 0
        let k = 0
        let t = []
        
        while (I < left.length && J < right.length) {
            if (left[I] < right[J]) {
                t.push(left[I])
                this.state.arr[k + l] = left[I]
                I = I + 1
                k++
            } else {
                this.state.arr[k + l] = right[J]
                t.push(right[J])
                J = J + 1
                k++
            }
        }
        while (I < left.length) {
            this.state.arr[k + l] = left[I]
            k++
            t.push(left[I])
            I = I + 1
        }
        while (J < right.length) {
            this.state.arr[k + l] = right[J]
            t.push(right[J])
            J = J + 1
            k++
        }
        console.log(t)
    }
    

    Вы также можете рассмотреть возможность использования более описательных имен переменных, чем I, J, k, l, r или t, а также задокументировать свой код, чтобы было ясно, что параметр r в mergeSort1 и merge1 является «включающим», т. Е. Указывает на последний элемент, который нужно отсортировать, а не на первый элемент после него.

...