K-way 병합 정렬(실전 전투)에 대한 자세한 설명
소개:
사실 K-way 병합 정렬은 여전히 매우 유용합니다. 가장 간단한 방법은 TB 수준의 데이터(TB 수준 검색 키워드라고 가정)와 같은 대량의 데이터를 정렬하려고 한다고 가정하는 것입니다. ), 하지만 우리의 메모리는 GB 수준에 불과합니다. 모든 데이터를 한 번에 로드하여 정렬할 수는 없지만 결국 결과를 원하므로 어떻게 해야 할까요? K-way 병합 정렬은 실제로 "분할 및 정복" 아이디어입니다. 우리는 Q 숫자를 정렬하고 싶지만 지금은 Q를 k로 나눌 수 없습니다. 그룹, 각 그룹은 n입니다. 숫자(k 분석: (1) k개의 정렬된 배열을 병합하는 방법은 무엇입니까? 앞서 힙에 대해 논의했기 때문에 당연히 힙의 정렬 효율성이 매우 높기 때문에 자연스럽게 힙을 사용하여 구현하는 것을 고려합니다. 오름차순으로 정렬해야 하기 때문에 최소한의 힙을 만듭니다. 최종 정렬 결과의 숫자는 항상 앞쪽이 작고 뒤쪽이 크기 때문에 모든 n 배열의 첫 번째 요소(최소 개수)를 최소 힙에 넣는 것을 고려하므로 최소 힙의 크기는 k 입니다. 이러한 방식으로 힙 구조를 조정하면 첫 번째 요소는 min(min(array1),min(array2)....min(arrayn))입니다. 이는 분명히 모든 숫자 중에서 가장 작은 요소입니다. (2) 모든 배열은 오름차순으로 정렬되므로 힙에서 최소 요소를 삭제하면 구멍을 채울 요소를 찾아야 합니다. 이렇게 하려면 배열에서 삭제된 요소가 있는 다음 요소를 찾아 힙에 채워야 합니다. (이것은 나라에서 가장 정예인 군인을 모집하여 정예 연대에 참여시키는 것과 약간 비슷합니다. 그러면 각 연대에서 가장 강한 병사가 모집됩니다. 만약 이 사람이 전투에서 불행하게도 죽으면, 그 사람 다음으로 두 번째인 사람을 찾으십시오. 동일한 연대. 엘리트 그룹의 가장 높은 전투 효율성을 항상 유지하기 위해 이 엘리트 그룹을 계속 지원합니다) 그러면 삭제된 힙 요소를 기반으로 삭제된 힙 요소가 위치한 배열을 찾는 방법은 무엇입니까? 이를 위해서는 현재 값과 현재 값이 있는 배열의 ID를 모두 포함하는 새로운 복합 유형을 생성해야 합니다. (3) 정렬된 각 배열은 가장 작은 요소가 지속적으로 손실되므로 정렬되지 않은 값이 점차 줄어들기 때문에 아직 정렬되지 않은 각 배열의 현재 위치를 유지하는 길이 k의 배열을 유지해야 합니다. 배열에 남아 있는 가장 작은 요소가 힙에 추가되면 현재 위치를 뒤로 이동해야 합니다. (4) 각 배열의 현재 위치가 뒤로 이동하면 결국 배열의 끝에 도달하게 됩니다. 이때 배열은 더 이상 숫자를 제공할 수 없습니다. (이는 정상입니다. 예를 들어 샵이 있습니다. 군대의 칼 중대에는 가장 뛰어난 사람들이 포함되어 있기 때문에 최종적으로 정예 그룹이 선정되면 항상 이 중대에서 선발되며 이 중대는 결국 아무도 없어야 하므로 찾을 수 없습니다. 현재 삭제된 번호가 있는 배열에서 다음 값을 선택해야 합니다. 이때 값이 있는 다음 배열 ID를 선택하고 해당 최소값을 선택해야 합니다. 방법은 arrayIdForDeletedData = (arrayIdForDeletedData + 1) % k입니다. (5) 결국 모든 배열 위치가 끝에 도달했습니다. 즉 모든 배열은 정렬에 관련되지 않은 값을 제공할 수 없으므로 이때 현재 힙이 비어 있는지 여부를 확인해야 합니다. 그렇지 않으면 n*k에서 가장 큰 숫자가 포함됩니다. 가장 작은 순서로 가장 큰 숫자를 출력하기 위해 deleteMin()을 수행합니다. 현재 힙이 이미 비어 있으면 루프에서 직접 뛰어내립니다. 따라서 최종 시간 복잡도는 O(n*logk) 코드: 위의 주요 기술적 세부 사항을 고려한 후에 여기 코드는 작성하기 쉽습니다. 먼저 정수를 캡슐화하는 값 객체와 그 정수가 나오는 배열을 정의합니다. 그런 다음 문제 해결의 핵심인 최소 힙을 정의합니다. 위에서 언급한 값 개체여야 합니다. 힙에 넣고 힙을 조정하면 이를 기반으로 한 계산이 모두 값 개체의 데이터 필드입니다. 마지막으로 K-way 결합기를 구현해 보겠습니다. 구현하기는 매우 쉽지만 일부 첨자 연산에 있어서는 특별한 주의가 필요합니다. 보편적이기를 원하기 때문에 k와 n이 모두 전달됩니다. 실제로 k와 n을 미리 계획하면 이러한 숫자를 내부적으로 전혀 유지할 필요가 없습니다. 최소값만 저장하면 되기 때문입니다. 더미. 실험: 마지막으로 32개의 숫자가 있고 각 방향에 8개의 숫자가 있으며 이 8개의 숫자가 이미 정렬되어 있다고 가정해 보겠습니다. 그런 다음 K-way 병합 알고리즘을 사용하여 32개 숫자를 모두 정렬합니다. 최종 실행 결과는 다음과 같습니다. 분명히 결과는 정확하며 우리 방법은 반복 값을 지원합니다. package com.charles.algo.kwaymerge;
/**
*
* 这个对象表明是一个可以跟踪来自于哪个数组的数据对象
* @author charles.wang
*
*/
public class TrackableData {
//data表明具体的值
private int data;
//comeFromArray表明这个值来自于哪一个数组
private int comeFromArray;
public TrackableData(int data,int comeFromArray){
this.data = data;
this.comeFromArray=comeFromArray;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public int getComeFromArray() {
return comeFromArray;
}
public void setComeFromArray(int comeFromArray) {
this.comeFromArray = comeFromArray;
}
}
package com.charles.algo.kwaymerge;
/**
* @author charles.wang
*
*/
public class MinHeap {
// 最小堆的存储是一个数组,并且为了计算,我们第一个位置不放内容
private TrackableData[] data;
// 堆的大小
private int heapSize;
// 当前元素的数量
private int currentSize;
public MinHeap(int maxSize) {
heapSize = maxSize;
// 创建一个比最大容纳数量多1的数组的作用是启用掉数组的头元素,为了方便运算,因为从1开始的运算更加好算
data = new TrackableData[heapSize + 1];
currentSize = 0;
}
/**
* 返回当前的堆是否为空
* @return
*/
public boolean isEmpty(){
if(currentSize==0)
return true;
return false;
}
/**
* 这里考察堆的插入,因为最小堆内部结构中数组前面元素总是按照最小堆已经构建好的,所以我们总从尾部插入 解决方法是: Step
* 1:先把当前的元素插入到数组的尾部 Step 2:递归的比较当前元素和父亲节点元素, Step
* 3:如果当前的元素小于父亲节点的元素,那么就把当前的元素上移,直到移不动为止
*
* @param value
* @return
*/
public MinHeap insert(TrackableData value) {
// 首先判断堆是否满了,如果满了就无法插入
if (currentSize == heapSize)
return this;
// 如果堆还没有满,那么说明堆中还有位置可以插入,我们先找到最后一个可以插入的位置
// currentPos表示当前要插入的位置的数组下标
int currentPos = currentSize + 1;
// 先插入到当前的位置,因为是从1开始的,所以数组下标运算也要+1
data[currentPos] = value;
// 然后比较当前元素和他的父亲元素
// 当前元素是data[currentPos] ,父亲元素是 data[(currentPos/2],一直遍历到根
TrackableData temp;
// 如果currentPos为1,表明是插入的堆中第一个元素,则不用比较
// 否则, 如果插了不止一个元素,则用插入位置的元素和其父元素比较
while (currentPos > 1) {
// 如果当前元素小于父亲元素,那么交换他们位置
if (data[currentPos].getData() < data[currentPos / 2].getData()) {
temp = data[currentPos / 2];
data[currentPos / 2] = data[currentPos];
data[currentPos] = temp;
// 更新当前位置
currentPos = currentPos / 2;
}
// 否则, 在假定已有的堆是最小堆的情况下,说明现在插入的位置是正确的,不用变换
else {
break;
}
}
// 插入完毕之后,吧当前的堆中元素的个数加1
currentSize++;
return this;
}
/**
* 这里考察堆的删除 因为是最小堆,所以肯定删除最小值就是删除堆的根元素,此外,还必须要调整剩余的堆使其仍然保持一个最小堆
* 因为有删除最小元素之后最小元素位置就有了个空位,所以解决方法是: Step 1:吧堆中最后一个元素复制给这个空位 Step
* 2:依次比较这个最后元素值,当前位置的左右子元素的值,从而下调到一个合适的位置 Step 3:从堆数组中移除最后那个元素
*/
public TrackableData deleteMin() {
// 如果最小堆已经为空,那么无法删除最小元素
if (currentSize == 0)
return null;
// 否则堆不为空,那么最小元素总是堆中的第一个元素
TrackableData minValue = data[1];
// 既然删除了最小元素,那么堆中currentSize的尺寸就要-1,为此,我们必须为数组中最后一个元素找到合适的新位置
// 堆中最后一个元素
TrackableData lastValue = data[currentSize];
// 先将堆中最后一个元素移动到最小堆的堆首
data[1] = lastValue;
// 把堆内部存储数组的最后一个元素清0
data[currentSize] = null;
// 并且当前的堆的尺寸要-1
currentSize--;
// 现在开始调整堆结构使其仍然为一个最小堆
int currentPos = 1; // 当前位置设置为根,从根开始比较左右
int leftPos = currentPos * 2;
TrackableData leftValue;
TrackableData rightValue;
TrackableData temp;
// 如果左位置和当前堆的总容量相同,说明只有2个元素了,一个是根元素,一个是根的左元素
if (leftPos == currentSize) {
// 这时候如果根左元素data[2]比根元素data[1]小,那么就交换二者位置
if (data[2].getData() < data[1].getData()) {
temp = data[2];
data[2] = data[1];
data[1] = temp;
}
}
else {
// 保持循环的条件是该节点的左位置小于当前堆中元素个数,那么该节点必定还有右子元素并且位置是左子元素位置+1
while (leftPos < currentSize) {
// 获取当前位置的左子节点的值
leftValue = data[leftPos];
// 获取当期那位置的右子节点的值
rightValue = data[leftPos + 1];
// 如果当前值既小于左子节点又小于右子节点,那么则说明当前值位置是正确的
if (data[currentPos].getData() < leftValue.getData()
&& data[currentPos].getData() < rightValue.getData()) {
break;
}
// 否则,比较左子节点和右子节点
// 如果左子节点小于右子节点(当然了,同时小于当前节点),那么左子节点和当前节点互换位置
else if (leftValue.getData() < rightValue.getData()) {
temp = data[currentPos];
data[currentPos] = leftValue;
data[leftPos] = temp;
// 同时更新当前位置是左子节点的位置,并且新的左子节点的位置为左子节点的左子节点
currentPos = leftPos;
leftPos = currentPos * 2;
}
// 如果右子节点小于左子节点(当然了,同时小于当前节点),那么右边子节点和当前节点互换位置
else {
temp = data[currentPos];
data[currentPos] = rightValue;
data[leftPos + 1] = temp;
// 同时更新当前位置是右子节点的位置,并且新的左子节点的位置为右子节点的左子节点
currentPos = leftPos + 1;
leftPos = currentPos * 2;
}
}
}
return minValue;
}
}
package com.charles.algo.kwaymerge;
import java.util.ArrayList;
import java.util.List;
/**
*
* 这个类用于演示K路合并
*
* @author charles.wang
*
*/
public class KWayMerger {
private KWayMerger() {
}
/**
* k路合并,这里的指导思想如下:
*
* (1)首先构造一个最小堆,其中堆中的元素初始值为每个数组中的最小元素
* (2)每次从最小堆中打印并且删除最小元素,然后把这个最小元素所在的数组中的下一个元素插入到最小堆中 (3)每次(2)结束后调整堆来维持这个最小堆
*/
public static void mergeKWay(int k, int n, List<int[]> arrays) {
// 这里存储了所有每个数组的当前的下标,在没有开始插入之前,每个数组的当前下标都设为0
int[] indexInArrays = new int[k];
for (int i = 0; i < k; i++) {
indexInArrays[i] = 0;
}
// 首先构造一个最小堆,其大小为k
MinHeap minHeap = new MinHeap(k);
// 第一步,依次吧每个数组中的第一个元素都插入到最小堆
// 然后把所有数组的下标都指向1
for (int i = 0; i < k; i++) {
// 这里每个都构造TrackableData对象:
// 其中:arrays.get(i)[0]表示它值为第i个数组的下标为0的元素(也就是第i个数组的第一个元素)
// i表示这个对象来自于第i个数组
minHeap.insert(new TrackableData(arrays.get(i)[0], i));
indexInArrays[i] = 1;
}
// 第二步,对最小堆进行反复的插入删除动作
TrackableData currentDeletedData;
TrackableData currentInsertedData;
int arrayIdForDeletedData;
int nextValueIndexInArray;
// 循环的条件是k个数组中至少有一个还有值没有被插入到minHeap中
while (true) {
// 这个变量维护了有多少个数组当前下标已经越界,也就是数组所有元素已经被完全处理过
int noOfArraysThatCompletelyHandled = 0;
// 就是去查询维护所有数组当前下标的数组,如果都越界了,那么就说明都比较过了
for (int i = 0; i < k; i++) {
if (indexInArrays[i] == n)
noOfArraysThatCompletelyHandled++;
}
// 如果所有的数组中的所有的值都比较过了,那么查看堆中内容是否为空。
if (noOfArraysThatCompletelyHandled == k) {
while (!minHeap.isEmpty()) {
currentDeletedData = minHeap.deleteMin();
// 打印出当前的数
System.out.print(currentDeletedData.getData() + " ");
}
break;
}
currentDeletedData = minHeap.deleteMin();
// 打印出当前的数
System.out.print(currentDeletedData.getData() + " ");
// 获取当前的被删的数来自于第几个数组
arrayIdForDeletedData = currentDeletedData.getComeFromArray();
// 获取那个数组的当前下标
nextValueIndexInArray = indexInArrays[arrayIdForDeletedData];
// 如果当前下标没有越界,说明当前数组中还有元素,则找到该数组中的下个元素
if (nextValueIndexInArray < n) {
// 构造新的TrackableData,并且插入到最小堆
currentInsertedData = new TrackableData(
arrays.get(arrayIdForDeletedData)[nextValueIndexInArray],
arrayIdForDeletedData);
minHeap.insert(currentInsertedData);
// 同时更新维护数组当前下标的数组,让对应数组的当前下标+1
indexInArrays[arrayIdForDeletedData]++;
}
// 如果当前下标已经越界,说明这个数组已经没有任何元素了,则找下一个有值的数组的最小元素
else {
while (true) {
arrayIdForDeletedData = (arrayIdForDeletedData + 1) % k;
// 获取那个数组的当前下标
nextValueIndexInArray = indexInArrays[arrayIdForDeletedData];
if (nextValueIndexInArray == n)
continue;
else {
// 构造新的TrackableData,并且插入到最小堆
currentInsertedData = new TrackableData(
arrays.get(arrayIdForDeletedData)[nextValueIndexInArray],
arrayIdForDeletedData);
minHeap.insert(currentInsertedData);
// 同时更新维护数组当前下标的数组,让对应数组的当前下标+1
indexInArrays[arrayIdForDeletedData]++;
break;
}
}
}
}
}
}
public static void main(String[] args) {
// 我们来演示K路合并,假设我们有4组已经排序了的数组,每组有8个数,则n=8,k=4
int[] array1 = { 4, 5, 7, 8, 66, 69, 72, 79 };
int[] array2 = { 3, 9, 42, 52, 53, 79, 82, 87 };
int[] array3 = { 1, 17, 21, 31, 47, 55, 67, 95 };
int[] array4 = { 6, 28, 49, 55, 68, 75, 83, 94 };
System.out.println("这里演示K路合并,其中每个数组都事先被排序了,并且长度为8,我们分4路合并");
System.out.println("数组1为:");
for(int i=0;i<array1.length;i++)
System.out.print(array1[i]+" ");
System.out.println();
System.out.println("数组2为:");
for(int i=0;i<array2.length;i++)
System.out.print(array2[i]+" ");
System.out.println();
System.out.println("数组3为:");
for(int i=0;i<array3.length;i++)
System.out.print(array3[i]+" ");
System.out.println();
System.out.println("数组4为:");
for(int i=0;i<array4.length;i++)
System.out.print(array4[i]+" ");
System.out.println();
List<int[]> arrayLists = new ArrayList<int[]>(4);
arrayLists.add(0, array1);
arrayLists.add(1, array2);
arrayLists.add(2, array3);
arrayLists.add(3, array4);
KWayMerger kWayMerger = new KWayMerger(4, 8, arrayLists);
System.out.println("排序后,结果为:");
kWayMerger.mergeKWay();
System.out.println();
}
위 내용은 K-way 병합 정렬(실전 전투)에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











배열의 반전된 표현입니다. 배열을 정렬된 형식으로 변환하는 데 필요한 변경 횟수입니다. 배열이 이미 정렬되어 있으면 반전이 0번 필요하지만, 다른 경우에는 배열이 반전되면 최대 반전 횟수에 도달하게 됩니다. 이 문제를 해결하기 위해 시간 복잡도를 줄이기 위한 병합 정렬 방법을 따르고 분할 정복 알고리즘을 사용하겠습니다. 숫자 순서를 입력합니다.(1,5,6,4,20) 숫자를 오름차순으로 정렬하는 데 필요한 반전 횟수를 출력합니다. 여기서 반전 수는 2입니다.첫 번째 반전:(1,5,4,6,20)두 번째 반전:(1,4,5,6,20)알고리즘 병합

PHP에서 병합 정렬을 구현하는 방법: 1. PHP 샘플 파일을 만듭니다. 2. "public function handler(){...}" 메서드를 정의합니다. 3. "private function mergeSort($a, $lo, $hi)를 사용합니다. )" {...}" 방법으로 데이터를 점진적으로 분해합니다. 4. "merge" 방법을 사용하여 분해된 데이터를 정렬한 다음 함께 병합합니다.

PHP의 병합 정렬 알고리즘에 대한 자세한 설명 소개: 정렬은 컴퓨터 과학의 일반적인 기본 문제 중 하나입니다. 데이터를 순서대로 배열하면 검색, 검색 및 수정 작업의 효율성이 향상됩니다. 정렬 알고리즘 중에서 병합 정렬은 매우 효율적이고 안정적인 알고리즘입니다. 이 기사에서는 코드 예제와 함께 PHP의 병합 정렬 알고리즘을 자세히 소개합니다. 병합 정렬의 원리 병합 정렬은 정렬할 배열을 두 개의 하위 배열로 나누고, 두 개의 하위 배열을 각각 병합 및 정렬한 후, 정렬된 하위 배열을 하나로 병합하는 분할 정복 알고리즘입니다.

C#에서 병합 정렬 알고리즘을 구현하는 방법 병합 정렬은 분할 정복 아이디어를 기반으로 한 고전적인 정렬 알고리즘으로 큰 문제를 여러 개의 작은 문제로 나눈 다음 점차적으로 작은 문제를 해결하고 결과를 병합하여 정렬을 완료합니다. 다음에서는 C#에서 병합 정렬 알고리즘을 구현하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 병합 정렬의 기본 아이디어는 정렬할 시퀀스를 여러 개의 하위 시퀀스로 분할하고, 별도로 정렬한 다음, 정렬된 하위 시퀀스를 순서가 지정된 시퀀스로 병합하는 것입니다. 이 알고리즘의 핵심은 하위 시퀀스의 분할 및 병합 작업을 구현하는 것입니다.

Java를 사용하여 병합 정렬 알고리즘을 구현하는 방법 소개: 병합 정렬은 분할 및 정복 방법을 기반으로 하는 고전적인 정렬 알고리즘으로 정렬할 배열을 계층별로 더 작은 하위 배열로 나눈 다음 병합하는 것입니다. 병합 작업을 통해 순서대로 하위 배열을 정렬된 전체 배열로 병합합니다. 이번 글에서는 Java를 이용하여 병합 정렬 알고리즘을 구현하는 방법을 자세히 소개하고 구체적인 코드 예제를 제공하겠습니다. 알고리즘 단계: 병합 정렬 알고리즘은 주로 분할, 병합 및 정렬의 세 단계로 구성됩니다. 스플릿: 먼저, 우리는

분할 및 정복 방법을 사용하여 PHP에서 병합 정렬 알고리즘을 구현하고 정렬 효율성을 향상시키는 방법은 무엇입니까? 병합 정렬은 분할 정복 방법을 사용하여 정렬할 배열을 두 부분으로 나누고 두 개의 하위 배열을 각각 정렬한 다음 정렬된 두 하위 배열을 하나로 병합하는 효율적인 정렬 알고리즘입니다. 정렬된 배열. 병합 정렬은 문제를 더 작은 하위 문제로 계속 나누고 솔루션을 하위 문제에 결합함으로써 정렬되지 않은 배열을 순서 있는 배열로 안정적으로 바꿀 수 있습니다. PHP에서 병합 정렬 알고리즘을 구현하고 정렬 효율성을 향상시킵니다.

병합 정렬 알고리즘과 Java에서의 응용에 대한 자세한 설명 1. 소개 병합 정렬은 분할 정복이라는 개념을 사용하여 배열을 두 개의 하위 배열로 나눈 다음 하위 배열을 재귀적으로 정렬합니다. -arrays, 그리고 마지막으로 두 개의 Sorted 하위 배열을 결합하여 하나의 정렬된 배열로 결합합니다. 이 기사에서는 Java의 병합 정렬 알고리즘과 해당 응용 프로그램을 자세히 분석하고 구체적인 코드 예제를 제공합니다. 2. 알고리즘 원리 병합 정렬의 주요 아이디어는 큰 배열을 두 개의 하위 배열로 나누고, 두 개의 하위 배열을 각각 정렬한 후, 최종적으로 순서가 있는 두 배열을 결합하는 것입니다.

개념: 주어진 요소 집합에 대해 어떤 배열이 병합 정렬의 최악의 시나리오로 이어질지 결정합니까? 점근적으로 병합 정렬은 항상 O(nlogn) 시간이 걸린다는 것을 알고 있지만 실제로 더 많은 비교가 필요한 경우에는 일반적으로 더 많은 시간이 걸립니다. 이제 기본적으로 일반적인 병합 정렬 알고리즘을 구현할 때 비교 횟수를 최대화하는 입력 요소 배열을 결정해야 합니다. 예 다음 요소 집합을 정렬된 배열로 간주합니다. 11121314151617181920212223242526 병합 정렬이 발생하는 최악의 입력 배열은 11191523132117251220162414221826입니다. 방법
