/*
1、思路:
对尚未排序的各元素从头到尾依次比较相邻的两个元素是否逆序(与欲排顺序相反)
若逆序就交换这两元素,经过第一轮比较排序后便可把最大(或最小)的元素排好
然后再用同样的方法把剩下的元素逐个进行比较,就得到了你所要的顺序
可以看出如果有 n 个元素,那么一共要进行 n-1 轮比较,第 i 轮要进行 j=n-i 次比较。
2、平均时间复杂度
O(n2)
3、平均空间时间复杂度
原地排序
4、稳定性
稳定
*/
void TestBubbleSort(int *pData, int iCount)
{
int iTemp = 0;
int i = 0;
int iPos = 0;
for (i = 0; i < iCount - 1; i++)
{
//每次遍历得到一个最大值
for (iPos = 0; iPos < iCount - 1 - i; iPos++)
{
if (pData[iPos] > pData[iPos + 1])
{
iTemp = pData[iPos];
pData[iPos] = pData[iPos + 1];
pData[iPos + 1] = iTemp;
}
}//endfor
}//endfor
}
/*
1、思路:
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据
每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,
将该元素插入到有序数列的合适位置中
2、平均时间复杂度
O(n2)
3、平均空间时间复杂度
原地排序
4、稳定性
稳定
*/
void TestInsertSort(int *pData, int iCount)
{
int iTemp = 0;
int i = 0;
int iPos = 0;
for (i = 1; i < iCount; i++)
{
iPos = i - 1;
iTemp = pData[i];
while(iPos >= 0)
{
if (pData[iPos] > iTemp)
{
pData[iPos + 1] = pData[iPos];
iPos--;
}
else
{
break;
}
}//endwhile
pData[iPos + 1] = iTemp;
}//endfor
}
/*
1、思路:
首先在所有的记录中选出键值最大的记录,把它与最后一个记录交换;
然后在其余的记录中再选出键值最大的记录与倒数第二个换
依此类推,直至所有记录排序完成。
在第i趟中,通过n-i次键值比较选出所需记录
2、平均时间复杂度
O(n2)
3、平均空间时间复杂度
原地排序
4、稳定性
不稳定
*/
void TestSelectSort(int *pData, int iCount)
{
int iMaxTemp = 0;
int iMaxPos = 0;
int i = 0;
int j = 0;
for (i = iCount - 1; i > 0; i--)
{
iMaxPos = i;
iMaxTemp = pData[i];
for (j = 0; j < i; j++)
{
if (pData[j] > pData[iMaxPos])
{
iMaxPos = j;
iMaxTemp = pData[iMaxPos];
}
}//endfor
if (i != iMaxPos)
{
pData[iMaxPos] = pData[i];
pData[i] = iMaxTemp;
}
}//endfor
}
/*
1、思路:
首先在数列中找出适当的轴心,将数列分成左右两部分,保证数列左半部分的元素都小于右半部分的元素,
然后分别对两部分进行排序,即重覆选择轴心,划分左右部分的过程。
2、平均时间复杂度
O(n log n)
3、平均空间时间复杂度
原地排序
4、稳定性
不稳定
*/
void TestQuickSort(int *pData, int iLeft, int iRight)
{
if (iLeft >= iRight)
{
return;
}
int i = iLeft;
int j = iRight;
int iBaseLineValue = pData[iLeft];
while(i < j)
{
while(i < iRight && pData[i] < iBaseLineValue)
{
i++;
}
while(j > iLeft && pData[j] > iBaseLineValue)
{
j--;
}
int iTemp = 0;
if (i <= j)
{
iTemp = pData[i];
pData[i] = pData[j];
pData[j] = iTemp;
}
}//endwhile
if (iLeft < i)
{
TestQuickSort(pData, iLeft, i - 1);
}
if (j < iRight)
{
TestQuickSort(pData, j + 1, iRight);
}
}
void Merge(int *pAData, int iLeft, int iMid, int iRight, int *pCData)
{
int iA = iLeft;
int iB = iMid + 1;
int iC = iLeft;
while(iA <= iMid && iB <= iRight)
{
if (pAData[iA] < pAData[iB])
{
pCData[iC++] = pAData[iA++];
}
else
{
pCData[iC++] = pAData[iB++];
}
}//endwhile
while (iA <= iMid)
{
pCData[iC++] = pAData[iA++];
}
while(iB <= iRight)
{
pCData[iC++] = pAData[iB++];
}
int iPos = 0;
for (iPos = iLeft; iPos <= iRight; iPos++)
{
pAData[iPos] = pCData[iPos];
}//endfor
}
/*
1、思路:
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,
即把待排序序列分为若干个子序列,每个子序列是有序的。
然后再把有序子序列合并为整体有序序列。
2、平均时间复杂度
O(n log n)
3、平均空间时间复杂度
O(n)
4、稳定性
稳定
*/
void TestMergeSort(int *pAData, int iLeft, int iRight, int *pCData)
{
if (iLeft == iRight)
{
pCData[iLeft] = pAData[iLeft];
}
else
{
int iMid = (iLeft + iRight)/2;
TestMergeSort(pAData, iLeft, iMid, pCData);
TestMergeSort(pAData, iMid + 1, iRight, pCData);
Merge(pCData, iLeft, iMid, iRight, pAData);
}
}
int LEFT(int i)
{
return 2 * i;
}
int RIGHT(int i)
{
return 2 * i + 1;
}
void MAX_HEAPIFY(int *pData, int iCount, int i)
{
int iTemp = 0;
int iLargest = i;
int iLeft = LEFT(i);
int iRight = RIGHT(i);
if ((iLeft <= iCount - 1) && (pData[iLeft] > pData[iLargest]))
{
iLargest = iLeft;
}
if ((iRight <= iCount - 1) && (pData[iRight] > pData[iLargest]))
{
iLargest = iRight;
}
if (iLargest != i)
{
iTemp = pData[iLargest];
pData[iLargest] = pData[i];
pData[i]= iTemp;
MAX_HEAPIFY(pData, iCount, iLargest);
}
}
void BUILD_MAX_HEAP(int *pData, int iCount)
{
int i = 0;
for (i = iCount/2; i >= 0; i--)
{
MAX_HEAPIFY(pData, iCount, i);
}
}
/*
1、思路:
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,
使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
找到数列中最大的数字,将其加在"有序列表"的末尾,并将其从原数列中删除。
重复2号步骤,直至原数列为空。
2、平均时间复杂度
O(n logn)
3、平均空间时间复杂度
原地排序
4、稳定性
不稳定
*/
void TestHeapSort(int *pData, int iCount)
{
BUILD_MAX_HEAP(pData, iCount);
int temp = 0;
int i = 0;
for (i = iCount -1; i >= 0; i--)
{
temp = pData[0];
pData[0] = pData[i];
pData[i] = temp;
MAX_HEAPIFY(pData, i-1, 0);
}
}
int MaxBit(int *pData, int iCount) //辅助函数,求数据的最大位数
{
int iMaxBit = 0;
int *pTmp = new int[iCount];
int i = 0;
for (; i < iCount; i++)
{
pTmp[i] = pData[i];
}//endfor
for(int i = 0; i < iCount; i++)
{
int p = 0;
while(pTmp[i]/10 > 0)
{
p++;
pTmp[i] = pTmp[i]/10;
}
if(iMaxBit < p+1) iMaxBit = p+1;
}
return iMaxBit;
}
/*
1、思路:
基数排序的主要思路是,将所有待比较数值(注意,必须是正整数)统一为同样的数位长度,
数位较短的数前面补零. 然后, 从最低位开始, 依次进行一次稳定排序.
这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列
2、平均时间复杂度
O(n)
3、平均空间时间复杂度
O(n)
4、稳定性
稳定
*/
void TestRadixSort(int *pData, int iCount) //基数排序
{
int iMaxBit = MaxBit(pData, iCount);
int *pTmp = new int[iCount];
int *pCount = new int[10]; //计数器
int i = 0, j = 0, k = 0;
int radix = 1;
for(i = 0; i< iMaxBit; i++) //进行iMaxBit次排序
{
for(j = 0; j < 10; j++)
{
pCount[j] = 0; //每次分配前清空计数器
}
for(j = 0; j < iCount; j++)
{
k = (pData[j]/radix) % 10; //统计每个桶中的记录数
pCount[k]++;
}
for(j = 1; j <= 10; j++)
{
pCount[j] = pCount[j-1] + pCount[j]; //将tmp中的位置依次分配给每个桶
}
for(j = iCount-1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
{
k = (pData[j]/radix) % 10;
pCount[k]--;
pTmp[pCount[k]] = pData[j];
}
for(j = 0; j < iCount; j++) //将临时数组的内容复制到data中
{
pData[j] = pTmp[j];
}
radix = radix*10;
}
}
/*
1、思路:
提出的“缩小增量”的排序方法。
它的作法不是每次一个元素挨一个元素的比较。
而是初期选用大跨步(增量较大)间隔比较,使记录跳跃式接近它的排序位置;
然后增量缩小;最后增量为 1 ,这样记录移动次数大大减少,提高了排序效率
2、平均时间复杂度
O(n log n)
3、平均空间时间复杂度
原地排序
4、稳定性
不稳定
*/
void TestShellSort(int *pData, int iCount)
{
int Step[4] = {9, 5, 3, 1};
int iTemp = 0;
int k = 0, s = 0, w = 0;
for(int i = 0; i < 4; i++)
{
k = Step[i];
s = -k;
for(int j = k; j < iCount; j++)
{
iTemp = pData[j];
w = j - k;//求上step个元素的下标
if(s == 0)
{
s = -k;
s++;
pData[s] = iTemp;
}
while((iTemp < pData[w]) && (w >= 0) && (w <= iCount))
{
pData[w+k] = pData[w];
w = w-k;
}
pData[w+k] = iTemp;
}
}
}
//主函数
void main()
{
int A[10] = {5, 3, 6, 10, 1, 9, 2, 4, 8, 7};
// TestBubbleSort(A, 10);
// TestInsertSort(A, 10);
// TestSelectSort(A, 10);
// TestQuickSort(A, 0, 9);
// TestMergeSort(A, 0, 9, C);
// TestHeapSort(A, 10);
// TestRadixSort(A, 10);
TestShellSort(A, 10);
}