博客公告:
(1)本博客所有博客文章搬迁至《博客虫》http://blogchong.com/
(4)该博客内容还会继续更新,不过会慢一些。
冒泡、选择、插入三种作为基本的排序算法是必须要掌握的,而在MapReduce的实际应用中。在Map阶段,k-v溢写时,采用的正是快排;而溢出文件的合并使用的则是归并;在Reduce阶段,通过shuffle从Map获取的文件进行合并的时候采用的也是归并;最后阶段则使用了堆排作最后的合并过程。
所以快排、归并以及堆排是必须要掌握的排序算法,这都在MapReduce内部使用的排序算法,学习Hadoop的必须过程。
所谓算法稳定性即能够保证排序前两个相等的数在排序中的过程中不会改变这两个数的顺序:例如Ai=Aj,Ai原来在Aj之前,但在排序之后Aj排在了Ai之前,这就是不稳定的表现。
不稳定的算法会导致元素交换增多(无效交换)。
在一个长度为N的无序数组中,在第一趟遍历N个数据,将最小的数值与第一个交换,第二趟遍历N-1次,将剩下中最小的与第二个元素交换...第N-1趟遍历剩下两个元素,判断大小交换位置即可,完成排序。
Ø
Ø
Ø
void SelectionSort(int *pDataArray, int iDataNum) {
for (int i = 0; i
int key = i; //用于交换的索引
for (int j = i + 1; j
if (pDataArray[j] key = j; } if (key != i){ int tmp = pDataArray[key]; pDataArray[key] = pDataArray[i]; //交换i值 pDataArray[i] = tmp; } } } 属于基本排序,性能较差,较少使用。 长度为N的无序数组,第一堂从1到N,依次和旁边的比较,大数右移,最后将最大的那个值滚动到N位置;第二趟类似前面,将第二大的值放到N-1位...直到第N-1趟完成排序。整个过程类似一个水泡依次网上冒,直到冒到最大的位置上。 Ø Ø Ø void BubbleSort(int *pDataArray, int iDataNum) { for (int i = 0; i for (int j = 0 ; j if (pDataArray[j] > pDataArray[j+1]) { int tmp = pDataArray[j]; pDataArray[j] = pDataArray[j+1]; pDataArrary[j+1] =tmp; } } } } 属于基本排序,性能较差,较少使用。 所谓插入排序即认为一个子序列是有序的,将一个数值插入到其中合适的位置中形成一个新的有序数列。长度为N的数组中,第一趟认为第一个数值是有序的,从第二个元素开始进行插入;第二趟从第三个元素插入...依次直到第N-1趟,第N个元素插入前面的有序数列完成排序。 Ø Ø Ø void InsertSor(int *pDataArray, int iDataNum) { for (int i = 1; i int j = i -1; int tmp = pDataArray[i]; if (j >= 0 && pDataArray[j] > tmp) { pDataArray[j+1] = pDataArray[j]; //将元素往后移,第i个元素已经放入tmp,不会被覆盖 j--; } if ( j != i - 1)//只要j改变了,则需要换位 pDataArray[j] = tmp; //将元素插入合适的位置 } } //在查找的过程中,考虑是否可以用二分查找的方式查找插入位置,但时间复杂度不变 二分查找: int BinSearch(int *pDataArray, int begin, int end, intSearchData) { int mid = (begin + end)/2; if (pDataArray[mid] == SearchData) return mid; else if (pDataArray[mid] else return BinSearch(pDataArray, begin, mid -1,SearchData); }//采用递归的方式进行二分查找,减少比较次数 属于基本排序算法,性能较低,较少使用 采用分而治之的思想,将无序数组进行分割,选择一个元素value(通常是第一个元素),第一次将小于Value的放在前段,大于value的放在后端;第二次排序分别对两段进行重复如上操作...进行递归操作,直到粒度划分到最小两个元素。 Ø Ø Ø //采用类似二分查找的递归方式(也是分段) int Split (int *pDataArray, int Begin, int End) { int key=pDataArray[Begin]; while (Begin while (Begin End--; if ( Begin != End) { pDataArray[Begin] = pDataArray[End]; Begin++; while (Begin Begin++; if (Begin != End) { pDataArray[End] = pDataArray[Begin]; End--;//将查找到的Begin元素放到之前的那个End位置(End位置元素已经移走可覆盖) } } } pDataArray[Begin] =key;//最终Begin=End,退出while,而Begin位为空,刚好把key填入 return Begin; }//针对一次排序 Void QSort (int *pDataArray, int Begin, int End){ if (End > Begin) { int Mid = Split(pDataArray, Begin, End); QSort (pDataArray, Begin, Mid - 1);//以该位置将以value值划分的数组分两段分别进行递归 QSort (pDataArray, Mid + 1, End); } } void QuickSort (int *pDataArray, int iDataNum){ QSort(pDataArray, 0, iDataNum - 1); } 比较常用的排序算法,Hadoop中Map阶段第一次排序默认使用的就是快排。 归并排序是将两个有序表合并成一个新的有序表,即把待排序的序列分成若干个有序的子序列,再把有序的子序列合并为整体有序序列。 而自底向上的归并则是将长度为N的无序数组切分成若干个N个有序子序列,再两两合并(起始时单元素为一个子序列),然后再将合并后的N/2(或者N/2+1)个子序列进行两两合并,依次类推得到一个完整的有序数组。 Ø Ø Ø //自底向上的归并 void Merge (int *pDataArray, *int pTempArray, int bIndex, intmIndex, int eIndex) { int mLenth = eIndex - bIndex; int i =0; int j =bIndex; int k = mIndex; while (j if (pDataArray[j] <= pDataArray[k]) { pTempArray[i++] = pDataArray[j]; j++; } else { pTemArray[i++] = pDataArray[k]; k++; } if (j == mIndex) while (k pTempArray[i++] = pDataArray[k++]; if (k == eIndex) while (j pTempArray[i++] = pDataArray[j++]; if (i = 0; i pDataArray[bIndex+i] = pTempArray[i]; } }//只是完成两个有序子序列的排序 void BottomUpMergeSort (int *pDataArray, int iDataNum) { int *pTempArray = (int *) malloc (sizeof (int) *iDataNum); int length = 1; //初始子序列的长度为1,都为有序(单元素) while (length int i = 0; for (; i + 2*length Merge(pDataArray, pTempArray, i, i + length, i + 2*length); //子序列的长度成倍数增长,1-->2-->4-->8,注意i的增长规律 if (i + length Merge(pDataArray, pTempArray, i, i + length, iDataNum); //最后一部分不成倍数的末尾部分(从i+length到iDataNum),直接归并 length *= 2; //子序列的长度增长规律,2倍增长 } free (pTempArray); //释放内存 } 在MapReduce的Reduce溢出文件Merge的过程中,默认使用的就是归并排序,将Map结果合并,所以掌握归并排序至关重要。 Ø Ø Ø Ø Ø Ø Ø Void HeapAdjust (int *pDataArray, int i, int iDataNum){ } if (rchild <= iDataNum && pDataArray[rchild] >pDataArray[max]) { //root依次和左子树,右子树比较,三者中找出最大值,进行max标记 } if (max != i){ } }//函数执行一次只进行一次交换(排除递归),进行递归的话则顺着max值往下走,直到形成大顶堆 Void HeapSort (int *pDataArray, int iDataNum){ } for (i = iDataNum; i >= 1; i--) { } } Read(读取) Read: Collect:分为map过程和partition过程,map根据inputSplit生成KV对,而Partition添加分区标记(辅助排序用),并写入环形缓存区; Spill: Shuffle阶段主要就是一个数据拷贝的过程,Map端合成的大文件之后,通过HTTP服务(jettyserver)拷贝到Reduce端。 如上可以看到,一个MapReduce过程涉及到了一次快排、两次归并以及一次堆排的操作。 因此在学习Hadoop的过程中,掌握这些基本的排序算法还是非常有用的。 2.2.4 实际应用:
2.3冒泡排序
2.3.1 设计思想
2.3.2 算法分析
2.3.3 算法实现
2.3.4 实际应用
2.4插入排序
2.4.1 设计思想
2.4.2 算法分析
2.4.3 算法实现
2.4.4 实际应用
2.5快速排序
2.5.1 设计思想
2.5.2 算法分析
2.5.3 算法实现
2.5.4 实际应用
2.6归并排序
2.6.1 设计思想
2.6.2 算法分析
2.6.3 算法实现
2.6.4 实际应用
2.7堆排序
2.7.1 设计思想
2.7.2 算法分析
2.7.3 算法实现
2.7.4 实际应用
3.1 MapReduce简单过程
3.1.1 Map阶段
3.1.2 Shuffle阶段
3.1.3 Reduce阶段
3.2 补充