排序算法总结(二)

来源:互联网 发布:mac 安装sass 编辑:程序博客网 时间:2024/06/06 19:55

归并排序算法思想是分而治之。下面将对分而治之算法排序做一个简单描述。

//归并排序之分而治之 void sort(E, n) { //对E中的n个元素排序 if(n >= k) {     i = n / k;     j = n - I;         令A由E的前i个元素组成;         令B由E的后j个元素组成;     sort(A, i);     sort(B, j);     merge(A, B, E, i, j);//把A和B合并到E }  else     对E插入排序}

    当K=2的时候,分而治之的排序算法称之为归并排序,严格的来说是二路归并排序,它的空间复杂度是O(n),时间复杂度为O(nlogn)。

    归并排序函数用一个数组a来存储元素序列E,并用a饭后排序后的序列。当序列E被划为2个子序列时,不必把他们分别复制到A和B中,只需要简单的记录他们在序列E中的左右边界。然后将拍熏后的子序列归并到一个新的数组b中去,最后再将它们赋值回a中。简明的算法如下:、

void mergeSort(T *a, int left, int right) { //对数组a[left,right-1]排序 if (left < right) { //至少有两个元素 int middle = (left + right) / 2; mergeSort(a, left, middle); mergeSort(middle + 1, right); merge(a, b, left, middle, right); //从a到b归并 copy(b, a, left, right);//将排序结果复制到a }}

    仔细观察这个归并程序会发现递归就是不断的将序列进行划分,直到序列的长度变为1,这时在进行归并,长度为1的子序列被归并成长度为2的子序列,长度为2的子序列被归并成长度为4的子序列,如此反复,直到只剩下一个有序序列,例子如下;

初始段  [8][4][5][1][3][6][2][7] 归并到 b [4 8] [1 5] [3 6] [2 7] 复制到 a [4 8] [1 5] [3 6] [2 7] 归并到 b [1 4 5 8] [2 3 6 7] 复制到 b [1 4 5 8] [2 3 6 7] 归并到 b [1 2 3 4 5 6 7 8]

    轮流的从a归并到b,从b归并到a,实际上消除了从b复制到a的过程。

用归并排序对数组a[0,n-1]进行排序的最终算法如下:

 template<class T> void mergeSort(T a[], int n) { T *b = new T[n]; int segmentSize = 1;                //记录子序列的长度 while (segmentSize < n) { mergePass(a, b, n, segmentSize); //从a到b的归并 segmentSize += segmentSize; mergePass(a, b, n, segmentSize); //从b到a的归并 segmentSize += segmentSize; } delete[]b; } //mergePass函数的作用是确定归并子序列的左右边界,真实的归并是在merge中完成 template <class T> void mergePass(T x[], T y[], int n, int segmentSize) { int i = 0; while (i <= n - 2 * segmentSize)//i+ 2 * segmentSize<n { //从x到y归并相邻的数据段 merge(x, y, i, i + segmentSize - 1, i + 2 * segmentSize - 1); i += 2 * segmentSize; } //少于两个慢数据段时 if (i + segmentSize < n) //剩余两个数据段 merge(x, y, i, i + segmentSize - 1, n - 1); else //剩余一个数据段 for (int j = i; j < n; j++) { y[j] = x[i]; } } template <class T> void merge(T c[], T d[], int startOfFirst, int endOfFirst, int endOfSencond) { //把相邻的数据段从c归并到d int first = startOfFirst;//第一个数据段的索引 int sencond = endOfFirst + 1;//第二个数据段的索引 result = startOfFirst;//归并数据段d的索引 while (first <= endOfFirst&&sencond <= endOfSencond) { if (c[first] <= c[sencond]) d[result++] = c[first++]; else d[resulst++] = c[sencond++]; } //归并剩余元素 if (first>endOfFirst) for (int q = sencond; q <= endOfSencond; q++) d[result++] = c[q];  //当归并序列的左边全不大于右边 else for (int q = first; q < endOfFirst; q++) { d[result++] = c[q];  //当归并序列的左边全不小于右边 } }


//法二template<class T>void merge(T data[], T result[],int start, int mid, int end) { int i, j, k; i = start; j = mid + 1;                        //避免重复比较data[mid] k = 0; while (i <= mid && j <= end)        //数组data[start,mid]与数组(mid,end]均没有全部归入数组result中去 { if (data[i] <= data[j])         //如果data[i]小于等于data[j] result[k++] = data[i++];    //则将data[i]的值赋给result[k],之后i,k各加一,表示后移一位 else result[k++] = data[j++];    //否则,将data[j]的值赋给result[k],j,k各加一 } while (i <= mid)                    //表示数组data(mid,end]已经全部归入result数组中去了,而数组data[start,mid]还有剩余 result[k++] = data[i++];        //将数组data[start,mid]剩下的值,逐一归入数组result while (j <= end)                    //表示数组data[start,mid]已经全部归入到result数组中去了,而数组(mid,high]还有剩余 result[k++] = data[j++];        //将数组a[mid,high]剩下的值,逐一归入数组result for (i = 0; i < k; i++)             //将归并后的数组的值逐一赋给数组data[start,end] data[start + i] = result[i];    //注意,应从data[start+i]开始赋值 }template<class T>void merge_sort(T data[], T result[], int start, int end) { if (start < end) { int mid = (start + end) / 2; merge_sort(data, result, start, mid);                    //对左边进行排序 merge_sort(data, result,mid + 1, end);                  //对右边进行排序 merge(data, result,start, mid, end);                    //把排序好的数据合并 } }



0 0
原创粉丝点击