目录
一. 选择排序
1.1 选择排序的实现思路
1.2 选择排序函数代码
1.3 选择排序的时间复杂度分析
二. 堆排序
2.1 堆排序的实现思路
2.2 堆排序函数代码
2.3 堆排序的时间复杂度分析
三. 冒泡排序
3.1 冒泡排序的基本思想
3.2 冒泡排序函数代码
3.3 冒泡排序的时间复杂度分析
前置说明:本文中所有排序算法均以排升序为例进行讲解。
选择排序,就是在一组数据中通过选出最大值(最小值的方法进行排序),假设要对具有n个数据的数组arr中的数据进行排序,具体实现步骤为:
如,对arr[6] = {3,4,0,5,1,6}排升序的过程为:
//数据交换函数
void swap(int* px, int* py)
{int tmp = *px;*px = *py;*py = tmp;
}//选择排序函数
//参数a为指向存储待排序数组首元素的指针,n为待排序元素的个数
void SelectSort(int* a, int n)
{//选择排序//每次筛选出未排序数据中最大和最小的那个,存在数组的前部和后部int begin = 0; //前部数据下标int end = n - 1; //后部数据下标while (begin < end){int mini = begin; //初始化最小的数据的下标int maxi = begin; //初始化最大的数据的下标int i = 0; //循环参数//for循环遍历每一个数据,找出最大的数据和最小的数据的下标for (i = begin + 1; i <= end; ++i){if (a[i] > a[maxi]){maxi = i;}if (a[i] < a[mini]){mini = i;}}//将最小的数据放在队首,队首数据放在原最小数据位置处//将最大的数据放在队尾,队尾数据放在原最大数据位置处swap(&a[begin], &a[mini]);if (maxi == begin){//如果首元素是最大的元素,那么swap(&a[begin], &a[mini])使队首数据不再是最大的数据//此时最大的数据被换到下标为mini的位置,更新maxi为minimaxi = mini;}swap(&a[end], &a[maxi]);--end;++begin;}
}
假设要对n个数据进行选择排序,总共要进行n/2次最大值最小值筛选操作,第一次筛选要遍历n个数据,第二次筛选要遍历n-2个数据,...,最后一次筛选要遍历2个数据或3个数据,设遍历一个数据就表示进行一次操作,总共要进行的操作次数为(假设最后一次遍历2个数据):
根据大O渐进法规则,选择排序的时间复杂度为。
注:当待排序数据为偶数个时,最后一次筛选要遍历2个数据,当待排序数据为奇数个时,最后一次筛选要遍历3个数据。
首先,要明确对于排升序和排降序,应该建大堆还是小堆,记住结论:
堆排序的操作流程如下(排升序):
//数据交换函数
void swap(DataType* px, DataType* py)
{int tmp = *px;*px = *py;*py = tmp;
}//向下调整函数
//a为存储待排序数据的数组,n为待排序数据的个数
void Adjustdown(DataType* a, int n, int parent)
{assert(a);int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] < a[child + 1])++child;if (a[parent] < a[child]){swap(&a[parent], &a[child]);parent = child;child = 2 * parent + 1;}else{break;}}
}//堆排序函数(升序)
void HeapSort(DataType* a, int n)
{assert(a);//先采用向下调整的方式将a中的数据建立为大堆//从后往前调整,叶子节点不用单独调整//因此,从第一个度不为0的节点开始往前调整到第一个节点即可int end = (n - 1 - 1) / 2;while(end >= 0){Adjustdown(a, n, end);--end;}//将a排为大堆后//将a的数据首尾交换,排除最后一个节点,将堆进行向下调整//重复进行上述操作n-1次,堆(数组)中的数据变为升序end = n - 1;while (end){swap(&a[0], &a[end]);Adjustdown(a, end, 0);--end;}
}
对N个数据进行堆排序,要先后进行建堆操作和向下调整操作。
建堆操作的时间复杂度
在堆排序中,采用向下调整的方法进行建堆。从倒数第二层开始将每个节点向下调整,假设层数为h,倒数第二层最多进行下调1次下调操作,倒数第三层最多进行2次下调操作,...,第二层最多进行h-2次下调操作,第一层最多进行h-1次下调操作,每层节点数和层数的关系为:,
为第
层节点数。综上,通过向下调整建堆要进行调整的次数最多为:
(1)
(2)
(2)-(1)得:
根据二叉树结构的性质:,
因此:。
根据大O渐进法,建堆操作的时间复杂度为:。
向下调整的时间复杂度
堆排序的基本思想是在建立堆之后交换首尾节点数据,然后向下调整根节点数据来实现的,假设堆中共有N个数据,总共要对N-1个数据向下调整,设二叉树的层数为h,每次向下调整最多调整h-1次,总共进行的向下调整操作的最多次数为:
根据大O渐进法,堆排序中调整过程的时间复杂度为:。
整个堆排序的时间复杂度
整个堆排序要进行建堆操作和向下调整操作,时间复杂度记,根据大O渐进法规则,堆排序时间复杂度可表示为:
。
冒泡排序的基本思想是交换,通过相邻两数的交换,达到排升序(降序)的目的,给定含有n个数据的数组arr,对arr中的数据排升序的操作步骤为:
图3.1展示了对数组arr[6] = {6,5,4,3,2,1}的第一趟排序的实现过程,经过一趟排序,arr中最大的值到了最后面的位置,第二趟排序对arr中的前5个数据进行相同的操作即可,第二趟排序结束后arr应当变为arr[6]={4,3,2,1,5,6}。
设想,如果单趟排序未发生数据交换,那就表示数据已经有序,数据有序就可以终止循环。因此,可以定义一个变量exchange来表示单趟排序是否发生数据交换,可以取exchange=1表示发生了数据交换,exchange=0表示没发生数据交换,每结束一次单趟循环都对exchange的值进行检查,如果exchange==0成立,则排序终止。
//冒泡排序函数
void bubbleSort(int* a, int n)
{int i = 0; //循环参数,表示冒泡排序趟数int j = 0; //循环参数,表示下标for (i = 0; i < n - 1; ++i) //单趟排序{int exchange = 0; //数据交换标识符,如果单趟排序发生数据交换为1,否则为0for (j = 0; j < n - 1 - i; ++j){//排升序,如果前面的数大于后面则交换if (a[j] > a[j + 1]){exchange = 1;int tmp = a[j];a[j] = a[j + 1];a[j + 1] = tmp;}}//如果单趟排序未发生数据交换flag=0,则表示数据已经有序,终止排序即可if (0 == exchange){break;}}
}
设待排序的数据个数为N,总共要进行N-1趟冒泡排序,假设冒泡排序过程中不发生break终止循环,第一趟冒泡排序最多进行N-1次数据交换,第二趟冒泡排序最多进行N-2次数据交换,...,最后一趟冒泡排序最多进行1次数据交换,因此,总共要进行数据交换的次数为:
根据大O渐进法规则,冒泡排序的时间复杂度为。
下一篇:HTTPS详解及HTTPS实验