排序
排序是个经典话题,但很容易忘掉,记下来温故知新。实现算法不一定最优,主要体现思想。
排序在很多算法书上都有涉及,本人再网上参考结合一些资料,整理有如下几种:(c++实现,默认从小到大,从左至右,总个数nCount)
备注:其中涉及的ArrSwap(),ArrMax(),ArrMin()不再赘述
void Bubble(int* Numbers, int nCount); //1.冒泡 void Select(int* Numbers, int nCount); //2.选择 void Insert(int* Numbers, int nCount); //3.插入 void ShellSort(int* Numbers, int nCount); //4.希尔 void Heap(int* Numbers, int nCount); //5.堆排 void Merge(int* Numbers, int nCount); //6.归并 void Bucket(int* Numbers, int nCount); //7.桶排 void Quick(int* Numbers, int nCount); //8.快速 void Base(int* Numbers, int nCount); //9.基数 void Count(int* Numbers, int nCount); //10.计数 void Topology(int* Numbers, int nCount); //11.拓扑
- 冒泡:从最左开始,左右比较,大的右调,到最后,最右边就是最大值。下次比较总数减1,如此往复总数为1时即算完成。code:
void Bubble(int* Numbers, int nCount) { for (int i = 0; i < nCount - 1; ++i) { for (int j = 1; j < nCount - i; ++j) { if (Numbers[j] < Numbers[j - 1]) ArrSwap(Numbers, j, j+1); } } }
- 选择:从最左到最右,找到最小值,与最左对换值;最左右移1再重复直至最左与最右重合即算完成,code:
void Select(int* Numbers, int nCount) { for (int i = 0; i < nCount - 1; ++i) { int nMin = i; for (int j = i + 1; j < nCount; ++j) { if (Numbers[j] < Numbers[nMin]) nMin = j; } ArrSwap(Numbers, nMin, i); } }
- 插入:假设a[1,n]是个有序序列,那么第n+1个插入合适位置使a[1,n+1]一样有序直至n+1=nCount;所谓合适即( a[cur-1] <= a[cur] <= a[cur+1] )code:
void Insert(int* Numbers, int nCount) { for (int nLast = 1; nLast < nCount; ++nLast) { for (int i = nLast; i > 0; --i ) (Numbers[i] < Numbers[i - 1]) ? ArrSwap(Numbers, i, i-1) : i = 0; } }
- 希尔:step=count/2;遍历时比较a[n],a[n+step]大数向右换(确保n+step < nCount),调整step=step/2再往复直到step=0时完毕(后续补图叙)。code:
void ArrShell(int* Numbers, int nCount, int nStep) { if (nStep == 0) return; int nNewCount = nCount - nStep; for (int i = 0; i < nNewCount; ++i) { if (Numbers[i] > Numbers[i + nStep]) ArrSwap(Numbers, i, i + nStep); } ArrShell(Numbers, nCount, nStep/2); } void ShellSort(int* Numbers, int nCount) { ArrShell(Numbers, nCount, nCount/2); }
- 堆排:按顺序填充完全二叉树,再调整使树LR<P,谓之堆。最尾换顶再削掉尾再调整成堆,如此往复被削掉的尾按次手机就是个有序序列(后续补图叙)。code:
void AdjustHeap(int* Numbers, int nCount, int nAim) { int nLeft = nAim*2; int nRight = nLeft + 1; int nMax = (nLeft != nCount && Numbers[nLeft-1] < Numbers[nRight-1]) ? nRight : nLeft; if (Numbers[nMax-1]>Numbers[nAim-1]) { ArrSwap(Numbers, nAim-1, nMax-1); if (nMax<=nCount/2) AdjustHeap(Numbers, nCount, nMax); } } void Heap(int* Numbers, int nCount) { do{ for (int i = nCount/2; i >= 1; --i) AdjustHeap(Numbers, nCount, i); ArrSwap(Numbers, 0, --nCount); } while (nCount > 1); }
-
归并:将序列一分为二,再分为二,直到不能再分其就是一个有序序列,该序列只有一个数,然后合并有序序列组成更大的有序序列(后续补图叙)。code:
void ArrMerge(int* LArr, int nL, int* RArr, int nR, int* AimArr, int nAim) { int nLi = 0, nRi = 0, nAi = 0; while (nLi < nL && nRi < nR) AimArr[nAi++] = (LArr[nLi] < RArr[nRi]) ? LArr[nLi++] : RArr[nRi++]; for (int i = nAi; i < nAim; ++i) AimArr[i] = (nLi == nL) ? RArr[nRi++] : LArr[nLi++]; } void Merge(int* Numbers, int nCount) { if (1 == nCount) return; int nLeft = nCount/2; int nRight = nCount - nLeft; int* LArr = new int[nLeft]; int* RArr = new int[nRight]; for (int i = 0; i < nCount; i++) (i < nLeft) ? (LArr[i] = Numbers[i]) : (RArr[i-nLeft] = Numbers[i]); Merge(LArr, nLeft); Merge(RArr, nRight); ArrMerge(LArr, nLeft, RArr, nRight, Numbers, nCount); delete[] LArr; delete[] RArr; }
-
桶排:满分100分,10分1级共10级(10个桶),分越高级越高,不同分数装入相应桶,桶内排序,全部桶排完按桶次序收集即可(其中桶中的排序是可选的)。code:
void Bucket(int* Numbers, int nCount) { int Max = Numbers[0]; int Min = Numbers[0]; for (int i = 0; i < nCount; i++) { if (Max < Numbers[i]) Max = Numbers[i]; if (Min > Numbers[i]) Min = Numbers[i]; } int nBuckets = 4; int nStep = (Max+1-Min)/4 + ((0 == (Max+1-Min) %4) ? 0 : 1); list<int>* Bucs = new list<int>[nBuckets]; for (int i = 0; i < nCount; i++) Bucs[(Numbers[i] - Min)/nStep].push_back(Numbers[i]); for (int i = 0; i < nBuckets ; i++) Bucs[i].sort(); int gIndex = 0; for (int i = 0; i < nBuckets ; i++) { for (list<int>::iterator it = Bucs[i].begin(); Bucs[i].end() != it; ++it) Numbers[gIndex++] = *it; } delete[] Bucs; }
- 快排:左大值右换,右小值左换,直到左==右,该数位置即定,其左右序列再如此往复则每个数都能找到自己的位置,使得L<=R。code:
void ArrQuick(int* Numbers,int nPosL,int nPosR) { if(nPosL >= nPosR) return; int nL = nPosL; int nR = nPosR; int temp = Numbers[nPosL]; while(nL != nR) { while(nL < nR && Numbers[nR] >= temp) nR--; if(nR > nL) Numbers[nL] = Numbers[nR]; while(nL < nR && Numbers[nL] <= temp) nL++; if(nL < nR) Numbers[nR] = Numbers[nL]; } Numbers[nL] = temp; ArrQuick(Numbers,nPosL,nL-1); ArrQuick(Numbers,nL+1,nPosR); } void Quick(int* Numbers, int nCount) { ArrQuick(Numbers, 0, nCount-1); }
- 基数:有桶排的思想。比如正整数,把个位数由0-9分到相应桶,再按桶次收集。更高位也照次方法直到最高位,最后收集的即为目标序列。code:
void Base(int* Numbers, int nCount) { int nMax = ArrMax(Numbers, nCount); int nLoop = 0; while (nMax > 0) { nLoop++; nMax = nMax/10; } for (int i = 0; i < nLoop; ++i) { list<int> allList[10]; for (int j = 0; j < nCount; ++j) { int nMod = 1; for (int ii = 0; ii <= i; ii++) nMod = nMod * 10; int nDiv = nMod / 10; int nWhichList = (Numbers[j] % nMod / nDiv); allList[nWhichList].push_back(Numbers[j]); } int nArrIndex = 0; for (int k = 0; k < 10; ++k) { for (list<int>::iterator it = allList[k].begin(); allList[k].end() != it; ++it) Numbers[nArrIndex++] = *it; } } }
- 计数:如序列值[0-9],则生成cnt序列,记录值的个数,再将其转为由左至右cnt值的累加值,序列写入cnt对应偏移位置即可。code:
void ArrCount(int* Numbers, int nCount, int nMax) { int* Couter = new int[nMax+1]; for (int i = 0; i< nMax+1; ++i) Couter[i] = 0; for (int i = 0; i <nCount; ++i) (Couter[Numbers[i]])++; for (int i = 1; i< nMax+1; ++i) Couter[i] = Couter[i] + Couter[i -1]; int* Temp = new int[nCount]; for (int i = 0; i < nCount; ++i) { Temp[Couter[Numbers[i]]-1] = Numbers[i]; Couter[Numbers[i]]--; } for (int i = 0; i < nCount; ++i) Numbers[i] = Temp[i]; delete[] Temp; delete[] Couter; } void Count(int* Numbers, int nCount) { int nMax = ArrMax(Numbers, nCount); ArrCount(Numbers, nCount, nMax); }
- 拓扑暂时还没有接触过,后续更新