쌓 기 정렬 - C \ # 실현

알고리즘 설명
       더미 정렬 (Heap Sort) 은 두 갈래 로 불 리 는 데이터 구 조 를 이용 하여 정렬 하 는 정렬 알고리즘 이다.
       이 진 지 는 내부 에 쌓 여 하나의 배열 을 유지 하고 비슷 한 완전 이 진 트 리 로 볼 수 있 으 며 나무의 모든 노드 는 배열 의 요소 에 대응 합 니 다.밑바닥 을 제외 하고 이 나 무 는 꽉 찼 다.
       이 진 더미 에는 유지 보수 그룹 과 관련 된 두 개의 속성 이 있 습 니 다.Length 는 배열 의 요소 개 수 를 나타 내 고 HeapSize 는 이 진 더미 에서 유지 하 는 배열 의 요소 개 수 를 나타 낸다 (배열 의 모든 요소 가 이 진 더미 의 유효 요소 가 아 닌 것).따라서 상기 정의 에 따 르 면 0 < = Heap Size < = Length.
       이 진 더 미 는 가장 큰 더미 와 가장 작은 더미 두 가지 유형 으로 나 눌 수 있다.가장 많은 더미 에서 이 진 트 리 의 모든 노드 는 아버지 노드 보다 크 지 않 습 니 다. 즉, A [Parent (i)] > = A [i] 입 니 다.최소 더 미 는 정반 대 입 니 다. A [Parent (i)] < = A [i].
       두 갈래 더 미 를 유지 하기 위해 최대 (작은) 더 미 를 사용 합 니 다. MaxHeapify (MinHeapify) 라 는 과정 을 호출 합 니 다.MaxHeapify 로 MaxHeapify 를 호출 할 때 뿌리 노드 를 Left (i) 와 Right (i) 로 가정 한 이 진 트 리 가 모두 최대 더미 입 니 다. 만약 에 A [i] 가 하위 노드 의 요소 보다 작 으 면 A [i] 와 그 하위 노드 의 비교적 큰 요 소 를 교환 합 니 다.그러나 이렇게 되면 교 환 된 하위 노드 를 루트 요소 로 하 는 이 진 더 미 는 최대 더미 의 성질 을 만족 시 키 지 못 할 수도 있 습 니 다. 이 때 는 모든 하위 이 진 더 미 는 최대 더미 의 성질 을 만족 시 킬 때 까지 MaxHeapify 방법 을 재 귀적 으로 호출 합 니 다.다음 그림 에서 보 듯 이:
       
       MaxHeapify (MinHeapify) 방법 을 호출 하여 루트 노드 가 A [i] 인 이 진 더미 가 최대 (작은) 더미 의 성질 을 만족 시 킬 때 우 리 는 좌우 하위 더 미 를 모두 최대 (작은) 더미 의 성질 을 만족 시 켰 다 는 가설 을 가지 기 때문에 정렬 할 배열 을 최대 (작은) 더미 로 구성 할 때 아래 에서 위로 MaxHeapify (MinHeapify) 방법 을 호출 해 야 합 니 다.
       최대 더 미 를 이용 하여 정렬 을 할 때 우 리 는 정렬 대기 배열 을 최대 더미 로 구성 합 니 다. 이때 A [0] (뿌리 노드) 는 배열 의 최대 요소 이 고 A [0] 를 A [n - 1] 와 교환 하면 A [0] 를 최종 적 으로 정확 한 정렬 위치 에 두 었 습 니 다.그리고 HeapSize 에서 1 을 빼 고 마지막 요 소 를 더미 에서 제거 합 니 다.그리고 MaxHeapify 방법 을 통 해 남 은 더 미 를 최대 로 바 꾸 고 이상 의 교환 을 반복 합 니 다.쌓 여 있 는 요소 가 두 개 밖 에 없 을 때 까지 이 동작 을 반복 합 니 다.최종 적 으로 얻 은 배열 은 오름차 순 으로 배 열 된 배열 이다.
       이 알고리즘 실현
       1. C \ # 에서 배열 의 시작 아래 에 0 으로 표시 되 어 있 음 을 알 수 있 으 므 로 아래 표 시 된 노드 의 부모 노드 와 좌우 부분 노드 를 계산 할 때 특히 조심해 야 합 니 다.
        private static int Parrent(int i)
        {
            return (i - 1) / 2;
        }

        private static int Left(int i)
        {
            return 2 * i + 1;
        }

        private static int Right(int i)
        {
            return 2 * i + 2;
        }

       2. 알고리즘 의 핵심 부분 은 MaxHeapify (MinHeapify) 방법 입 니 다. 알고리즘 설명 에 따 르 면 다음 코드 는 정수 배열 에 대한 최대 집적 화 와 최소 집적 방법, 그리고 일반적인 버 전 을 실현 합 니 다.
        private static void MaxHeapify(int[] array, int i, int heapSize)
        {
            int left = Left(i);
            int right = Right(i);

            int largest = i;
            if (left < heapSize && array[left] > array[i])
            {
                largest = left;
            }

            if (right < heapSize && array[right] > array[largest])
            {
                largest = right;
            }

            if (largest != i)
            {
                Exchange(ref array[i], ref array[largest]);
                MaxHeapify(array, largest, heapSize);
            }
        }

        private static void MinHeapify(int[] array, int i, int heapSize)
        {
            int left = Left(i);
            int right = Right(i);

            int smallest = i;
            if (left < heapSize && array[left] < array[i])
            {
                smallest = left;
            }

            if (right < heapSize && array[right] < array[smallest])
            {
                smallest = right;
            }

            if (smallest != i)
            {
                Exchange(ref array[i], ref array[smallest]);
                MinHeapify(array, smallest, heapSize);
            }
        }

        private static void MHeapify(T[] array, int i, int heapSize, Comparison comparison)
        {
            int left = Left(i);
            int right = Right(i);

            int extremumIndex = i;
            if (left < heapSize && comparison(array[left], array[i]) > 0)
            {
                extremumIndex = left;
            }

            if (right < heapSize && comparison(array[right], array[extremumIndex]) > 0)
            {
                extremumIndex = right;
            }

            if (extremumIndex != i)
            {
                Exchange(ref array[extremumIndex], ref array[i]);
                MHeapify(array, extremumIndex, heapSize, comparison);
            }
        }

       3. 구조 가 가장 크다.밑 에서 위로 구 조 를 하 는 것 이 눈 에 띈 다.
        private static void BuildMaxHeap(int[] array)
        {
            for (int i = array.Length / 2 - 1; i >= 0; i--)
            {
                MaxHeapify(array, i, array.Length);
            }
        }

        private static void BuildMinHeap(int[] array)
        {
            for (int i = array.Length / 2 - 1; i >= 0; i--)
            {
                MinHeapify(array, i, array.Length);
            }
        }

        private static void BuildMHeap(T[] array, Comparison comparison)
        {
            for (int i = array.Length / 2 - 1; i >= 0; i--)
            {
                MHeapify(array, i, array.Length, comparison);
            }
        }

       4 더미 정렬 알고리즘.다음은 정수 배열 의 오름차 순 정렬, 내림차 순 정렬 과 일반 버 전 이다.오름차 순 정렬 구 조 는 최대 더미 이 고 내림차 순 정렬 은 구조의 최소 더미 입 니 다.
        public static void HeapSort(int[] array)
        {
            BuildMaxHeap(array);
            for (int i = array.Length - 1; i > 0; i--)
            {
                Exchange(ref array[i], ref array[0]);
                MaxHeapify(array, 0, i);
            }
        }

        public static void HeapDesSort(int[] array)
        {
            BuildMinHeap(array);
            for (int i = array.Length - 1; i > 0; i--)
            {
                Exchange(ref array[i], ref array[0]);
                MinHeapify(array, 0, i);
            }
        }

        public static void HeapSort(T[] array, Comparison comparison)
        {
            BuildMHeap(array, comparison);
            for (int i = array.Length - 1; i > 0; i--)
            {
                Exchange(ref array[i], ref array[0]);
                MHeapify(array, 0, i, comparison);
            }
        }

       
세 가지 다른 코드 의 조직 방식
       상술 한 코드 는 일반적인 더미 정렬 의 실현 방식 이다.그러나 C \ # 로 쌓 기 정렬 을 실현 하 는 이상 가능 한 한 대상 을 대상 으로 하 는 방식 을 고려 하여 알고리즘 을 실현 해 야 한다.상기 코드 를 감안 하면 노드 의 하위 노드, 부모 노드, 유지 최대 (작은) 더미, 최대 (작은) 더미 구축 등 방법 을 구 하 는 것 자체 가 이러한 데이터 구조 자체 에 대한 작업 에 속한다.따라서 이 를 하나의 데이터 구조 류 로 봉 하여 클래스 에서 관련 정렬 작업 을 하 는 것 을 고려 할 수 있다.다음 과 같다.
    public class Heap
    {
        #region Fields

        private int _heapSize = 0;
        private T[] _array = null;

        #endregion

        #region Properties

        public int HeapSize
        {
            get { return _heapSize; }
            set { _heapSize = value; }
        }

        #endregion

        #region Constructors

        public Heap(T[] array, int heapSize)
        {
            _array = array;
            
            if(heapSize > array.Length)
            {
                Exception ex = new Exception("The heap size is larger than the array length");
                throw (ex);
            }
            _heapSize = heapSize;
        }

        public Heap(T[] array)
        {
            _array = array;
            _heapSize = array.Length;
        }

        #endregion

        #region Methods

        private int Parrent(int index)
        {
            return (index - 1) / 2;
        }

        private int Left(int index)
        {
            return 2 * index + 1;
        }

        private int Right(int index)
        {
            return 2 * index + 2;
        }

        private void MHeapify(int rootIndex, Comparison comparison)
        {
            int leftChildIndex = Left(rootIndex);
            int rightChildIndex = Right(rootIndex);

            int extremumIndex = rootIndex;
            if (leftChildIndex < _heapSize && comparison(_array[leftChildIndex], _array[rootIndex]) > 0)
            {
                extremumIndex = leftChildIndex;
            }

            if (rightChildIndex < _heapSize && comparison(_array[rightChildIndex], _array[extremumIndex]) > 0)
            {
                extremumIndex = rightChildIndex;
            }

            if (extremumIndex != rootIndex)
            {
                Helper.Exchange(ref _array[extremumIndex], ref _array[rootIndex]);
                MHeapify(extremumIndex, comparison);
            }
        }

        private void BuildMHeap(Comparison comparison)
        {
            for (int i = _array.Length / 2 - 1; i >= 0; i--)
            {
                MHeapify(i, comparison);
            }
        }

        public void Sort(Comparison comparison)
        {
            BuildMHeap(comparison);
            for (int i = _array.Length - 1; i > 0; i--)
            {
                Helper.Exchange(ref _array[i], ref _array[0]);
                _heapSize--;
                MHeapify(0, comparison);
            }
        }

        #endregion
    }
   public class Helper
    {
        public static void Exchange(ref T x, ref T y)
        {
            T temp = x;
            x = y;
            y = temp;
        }
    }

       
4 알고리즘 분석
       1. 전체 더미 가 정렬 되 는 과정 에서 기 존의 배열 에서 요 소 를 조작 할 뿐 상수 의 추가 공간 만 필요 합 니 다.따라서 쌓 기 정렬 은 원래 의 주소 정렬 알고리즘 으로 그 공간 복잡 도 는 O (1) 이다.
       2. 매 라운드 의 최대 (작은) 화 더미 에서 가장 큰 요 소 를 지정 한 최종 위치 에 놓 기 위해 더미 의 뿌리 요소 와 마지막 요 소 를 직접 교환 합 니 다. 이 는 더미 와 마지막 요소 의 값 이 같은 요소 와 마지막 요소 의 상대 적 인 위 치 를 개편 할 수 있 습 니 다.따라서 쌓 기 순 서 는 불안정 하 다.
       3. 쌓 기 정렬 의 전체 과정 에서 가장 오래 걸 리 는 작업 은 최대 (작은) 쌓 기 성질 의 MaxHeapify (MinHeapify) 과정 을 유지 하 는 데 있다.MaxHeapify (MinHeapify) 의 경우, 실행 시간의 귀속 식 은 다음 과 같 습 니 다.
       T(n) <= T(2n / 3) + θ(1)
       주 정리 에 따 르 면 T (n) = O (lgn) 를 알 수 있다.
       따라서 쌓 기 정렬 의 시간 복잡 도 는 T (n) = nlgn 이다.
       5 운행 결과
       마찬가지 로 계수 요소 의 비교 횟수 에 따라 알고리즘 의 집행 규 모 를 평가 할 수 있다.
       알고리즘 의 범 형 실현 버 전에 서 의뢰 로 들 어 오 는 비교 방법 에 계수 문 구 를 넣 으 면 비교 문 구 를 쉽게 실행 할 수 있 습 니 다.
private static int AscComparison(int x, int y)        
{        
    count++;       
    if (x > y)        
    {        
        return 1;        
    }        
    else if (x == y)        
    {        
        return 0;        
    }        
    else        
    {        
        return -1;        
    }        
} 
       이 알고리즘 의 평균 운행 상황 을 테스트 하기 위해 10000 개의 무 작위 배열 을 정렬 하여 평균 을 추출 합 니 다.
static void Main(string[] args)        
{        
    for (int i = 0; i < 10000; i++)        
    {        
        // 1-100   10            
        int[] randomIntArray = DataCreator.CreateRandomIntArray(1, 100, 10);        
        Heap heap = new Heap(randomIntArray);
        heap.Sort(AscComparison);     
        PrintAarry(randomIntArray);        
    }        
    int averageCount = count / 10000;        
    Console.WriteLine(averageCount);        
}  

       테스트 결과:
       n = 10,   averageCount = 38= 1.144* 10 * lg10; 
       n = 100,   averageCount = 1026= 1.544 * 100 * lg100;        n = 1000, averageCount = 16851 = 1.691 * 1000 * lg1000;
       n = 10000, averageCount = 235371 =  1.771 * 10000 * lg10000; 
       테스트 결 과 를 통 해 알 수 있 듯 이 정렬 알고리즘 의 평균 연산 시간 복잡 도 역시θ(nlgn)。

좋은 웹페이지 즐겨찾기