排序:将一连串记录按照关键字的大小(从大到小或从小到大)进行排列。
稳定性:如果两个大小相同的关键字的相对位置在排序前和排序后是一样的(Ai等于Aj,排序前Ai 在Aj的前面,排序后Ai 还是在Aj的前面),那么这种算法就是稳定的。
稳定的排序算法有:冒泡排序、直接插入排序、归并排序、基数排序
不稳定的排序算法有:选择排序、快速排序、希尔排序、堆排序
冒泡排序:
每轮都是从第一个元素开始,按顺序比较相邻的2个元素,将大的元素放到后面,小的元素放到前面。这样经过第一轮后,最大的元素位于最后的位置。第二轮后第二大的元素将位于倒数第2的位置。经过N-1轮后,所有的元素都将按从小到大排列。
最好的时间复杂度为O(n),最坏的时间复杂度为O(n^2),平均时间复杂度为O(n^2)。
c++代码:
void BubbleSort(int iArr[], int iNum)
{
int i, j, iTemp;
for (i = 0; i < iNum - 1; i++) //总共进行iNum-1轮
{
for (j = 0; j < iNum - i - 1; j++) //每轮要比较的次数为iNum-i-1
{
if (iArr[j] > iArr[j + 1]) //将大的元素往后放
{
iTemp = iArr[j];
iArr[j] = iArr[j + 1];
iArr[j + 1] = iTemp;
}
}
}
}
直接插入排序:
每次从无序表中取出第一个元素,把它插入到有序表的适合位置,使有序表仍然有序。
平均时间复杂度为O(n^2)。
c++代码:
void InsertionSort(int iArr[], int iNum)
{
int i, j, iTemp;
for (i = 1; i < iNum; i++) //总共进行iNum-1轮
{
iTemp = iArr[i]; //将当前要插入的元素先备份
j = i - 1; //从要插入元素的前一个元素开始比较
while((j >= 0) && (iArr[j] > iTemp))
{
//将比iTemp大的元素往后移一个位置
iArr[j + 1] = iArr[j];
j--;
}
//如果j不等于i-1,说明这一轮有元素移动
if (j != i - 1)
{
iArr[j + 1] = iTemp;//将要插入的元素放到适当的位置
}
}
}
归并排序:
假设有一个数列{2,0,1,6,3,8,7,4,5,9}
第一次归并后:{0,2},{1,6},{3,8}{4,7},{5,9}
第二次归并后:{0,1,2,6},{3,4,7,8},{5,9}
第三次归并后:{0,1,2,3,4,6,7,8},{5,9}
第四次归并后:{0,1,2,3,4,5,6,7,8,9}
平均时间复杂度为O(nlogn)。
基数排序:
先将元素按个位数大小进行排序,再将元素按十位数大小进行排序····
假设有一数列{73,22,93,43,55,14,28,65,39,81}
按个位数排序后:{81,22,73,93,43,14,55,65,28,39}
按十位数排序后:{14,22,28,39,43,55,65,73,81,93}
平均时间复杂度为O(n)。
c++代码:
void RadixSort(int iArr[], int iNum)
{
int iMax = iArr[0];
for (int i = 1; i < iNum; i++)//获取序列的最大元素
{
if (iMax < iArr[i])
iMax = iArr[i];
}
int iLoop = 0;
while (iMax != 0)//计算最大元素的位数
{
iLoop++;
iMax /= 10;
}
int iRow;
for (int i = 1; i <= iLoop; i++)//根据最大位数进行循环
{
//iBackup的第一列用来存放对应行中存放的元素个数
int iBackup[10][20] = {0};
int iNumber = pow(10.0, i - 1);
for (int j = 0; j < iNum; j++)//遍历所有元素
{
//第一轮计算个位数,第二轮计算十位数•••
iRow = (iArr[j] / iNumber) % 10;
//将元素按照iRow的大小存放到iBackup对应的行中
int ilist = ++iBackup[iRow][0];
iBackup[iRow][ilist] = iArr[j];
}
int k = 0;
//按顺序将iBackup中的元素放回iArr数组中
for (int m = 0; m < 10; m++)
{
for (int n = 1; n <= iBackup[m][0]; n++)
{
iArr[k++] = iBackup[m][n];
}
}
}
}
选择排序:
每一次从待排序的元素中选出最小的一个元素,放在序列的起始位置。
平均时间复杂度为O(n^2)。
c++代码:
void SelectSort(int iArr[], int iNum)
{
for (int i = 0; i < iNum - 1; i++) //总共进行iNum-1轮
{
int iMin = i;//iMin为本轮中最小元素的下标
for (int j = i + 1; j < iNum; j++)//查找本轮最小元素
{
if (iArr[iMin] > iArr[j])
{
iMin = j;
}
}
if (iMin != i)
{
//将本轮最小元素放在序列开头
int iSwap = iArr[i];
iArr[i] = iArr[iMin];
iArr[iMin] = iSwap;
}
}
}
快速排序:
通常选择序列的第一个元素为关键数据,将小于关键数据的元素放在关键数据前面,将大于关键数据的元素放在关键数据后面。然后再对关键数据前后两个序列做同样的递归操作。
平均时间复杂度为O(nlogn)。
c++代码:
void QuickSort(int iArr[], int iLeft, int iRight)
{
int i = iLeft;
int j = iRight;
int iKey = iArr[i];//将当前区间的第一个元素作为关键数据
if (iLeft >= iRight)
return ;//不能再划分,直接返回
while(i < j)
{
//将比iKey小的元素往前放
while(i < j && iArr[j] >= iKey)
{
j--;
}
iArr[i] = iArr[j];
//将比iKey大的元素往后放
while(i < j && iArr[i] <= iKey)
{
i++;
}
iArr[j] = iArr[i];
}
iArr[i] = iKey;//将iKey放中间
QuickSort(iArr, iLeft, i - 1);//继续递归操作
QuickSort(iArr, i + 1, iRight);
}
希尔排序:
希尔排序是插入排序的一种。它是把元素按照下标的一定增量分组,再对每组使用直接插入排序。随着增量逐渐减少,每组包含的元素越来越多。当增量减少到1时,所有的元素正好分成1组。
平均时间复杂度为O(n^1.25。
c++代码:
void ShellSort(int iArr[], int iNum)
{
int i, j, iGap, k;
for (iGap = iNum / 2; iGap > 0; iGap /= 2)//增量
{
for (i = 0; i < iGap; i++)//遍历每个分组
{
for (j = i + iGap; j < iNum; j += iGap)//遍历每个分组中的元素
{
//对分组进行直接插入排序
int iTemp = iArr[j];
for (k = j - iGap; k >= 0 && iArr[k] > iTemp; k -= iGap)
{
iArr[k + iGap] = iArr[k];
}
iArr[k + iGap] = iTemp;
}
}
}
}
堆排序:
堆排序是利用了完全二叉树,它将元素列表组织成一个完全二叉树。第一轮操作过后,最大的元素将位于根节点,然后将根节点元素和最后一个节点元素对换。第二轮操作过后,第二大的元素将位于根节点(剩下N-1个元素中最大的元素),然后将根节点元素和倒数第二个节点元素对换。继续进行下去,直到整个二叉树是从小到大排列的。
平均时间复杂度为O(nlogn)。
c++代码:
void HeapAdjust(int iArr[], int i, int iNum)
{
//i是要调整的节点,执行该函数后以i为根节点的子树中,
//i节点的值最大
int iLchild = 2 * i + 1;
int iRchild = 2 * i + 2;
int iMax = i;
if (i <= iNum / 2 - 1)
{
if (iLchild < iNum && iArr[iLchild] > iArr[iMax])
{
iMax = iLchild;
}
if (iRchild < iNum && iArr[iRchild] > iArr[iMax])
{
iMax = iRchild;
}
if (i != iMax)
{
int iTemp = iArr[i];
iArr[i] = iArr[iMax];
iArr[iMax] = iTemp;
HeapAdjust(iArr, iMax, iNum);
}
}
}
//将数组组织成完全二叉树
void BuildHeap(int iArr[], int iNum)
{
for (int i = iNum / 2 - 1; i >= 0; i--)
{
HeapAdjust(iArr, i, iNum);
}
}
void HeapSort(int iArr[], int iNum)
{
BuildHeap(iArr, iNum);
for (int i = iNum - 1; i > 0; i--)
{
//将当前最大值与当前最后的节点对换
int iTemp = iArr[0];
iArr[0] = iArr[i];
iArr[i] = iTemp;
//对换后,重新调整
HeapAdjust(iArr, 0, i);
}
}