注:
重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。(注:百度百科)
//elemType 为数组元素类型,常见有 int,long,char,short ,double,float等;也可以是自定义类型,如不改变以下格式,可以尝试重载 “<” 符号;
void bubbleSort (elemType arr[], int len) {
elemType changeTemp;
for (int i = 0; i < len-1; i++) {
for (int j = 1;j < len -i; j++) {
if (arr[j] < arr[j-1]) {
changeTemp = arr[j];
arr[i] = arr[j - 1];
arr[j - 1] = changeTemp;
}
}
}
}
冒泡排序 (稳定排序算法)
第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
void selectSort(elemType arr[],int lenght) {
int minIndex = -1;
for (int i = 0; i < lenght-1; i++) {
minIndex = i;
for (int j = i+1;j < length; j++) {
if ( arr[j] < arr[minIndex]) {
minIndex = j;
}
}
if (minIndex != i ) {
exchange arr[i] and arr[minIndex];
}
}
}
插入排序是指在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。按照此法对所有元素进行插入,直到整个序列排为有序的过程,称为插入排序 。
void insertSort(elemType arr[], int length) {
elemType changeTemp;
int j = 0;
for (int i = 1; i < length ; i++ ) {
changeTemp = arr[i];
for (j = i-1; j >= 0; j--) {
if (arr[j] < changeTemp) {
break;
}
arr[j+1] = arr[j];
}
arr[j+1] = changeTemp
}
}
快速排序: 简单来说可以概括为东拆西补 或 西拆东补,一边拆一边补,每次递归实现了将数组的小于标准元素(可以指定数组中任意一个,一边取第一个元素)的元素放在左侧,大于标准元素的放在右侧;对左右两侧的元素执行相同的操作(一般用递归实现)
int getSortIndex(elemType arr[],int low,int high) {
elemType standard = arr[low]; //取第一个元素作为标准元素,造成一个空位;
while(low < high) {
//从右侧寻找 比standard 小的元素;补左侧空位;
while(low < high && arr[high] >= standard) {
high--;
}
arr[low] = arr[high];
//从左侧寻找 比standard 大的元素;补右侧空位;
while(low < high && arr[low] <= standard) {
low++;
}
arr[high] = arr[low];
}
//最后将标准元素填充到最后的空位上
arr[low] = standard;
return low; //返回不需要再变动元素的位置
}
void quickSort(elemType arr[], int low, int high) {
if (low < high) {
int index = getSortIndex(arr,low,high);
quickSort(arr,low,index-1);
quickSort(arr,index+1,high);
}
}
代码采用递归的实现,每次递归(满足low < high)执行三个动作:
(1). 对数组进行东拆西补,西拆东补,直至将大于标准元素和小于标准元素分开,并返回不需要再变动元素的位置;
(2). 对小于标准元素的数组进行递归;
(3). 对大于标准元素的数组进行递归;
快速排序:不稳定排序
时间复杂度:O(nlog₂n)
堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
void maxHeapify(elemType arr[],int start, int end) {
int parent = start;
int child = 2 * parent + 1; //left child
while(child <= end) {
if (child + 1 <= end && arr[child] < arr[child + 1] ) {
child++; //right child
}
if (arr[parent] >arr[child]) {
return; //不需要交换
} else {
exchange arr[parent] and arr[right];
parent = child;
child = 2 * parent + 1;
}
}
}
void heapsort(elemType arr[],int length) {
int i ;
//初始化,i 从最后一个父节点开始调整
for (i = length / 2 -1; i >= 0; i--) {
maxHeapify(arr,i,length-1);
}
for (i = length -1; i > 0 ;i--) {
exchange arr[0] and arr[i];
maxHeapify(arr,0, i-1);
}
}
在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:
(1). 最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点;
(2). 创建最大堆(Build Max Heap):将堆中的所有数据重新排序
(3). 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算
最大堆排序:不稳定排序
时间复杂度:O(nlog₂n)
计数排序对输入的数据有附加的限制条件:
1、输入的线性表的元素属于有限偏序集S;
2、设输入的线性表的长度为n,|S|=k(表示集合S中元素的总数目为k),则k=O(n)。
在这两个条件下,计数排序的复杂性为O(n)。
计数排序的基本思想是对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数(此处并非比较各元素的大小,而是通过对元素值的计数和计数值的累加来确定)。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。例如,如果输入序列中只有17个元素的值小于x的值,则x可以直接存放在输出序列的第18个位置上。当然,如果有多个元素具有相同的值时,我们不能将这些元素放在输出序列的同一个位置上,因此,上述方案还要作适当的修改。
void CountSort(int data[],int n) {
int i,j,count,*data_p,temp;
data_p = new int[n];
//初始化data_p
for(i = 0; i < n; i++) {
data_p[i] = 0;
}
for(i = 0; i < n; i++) {
count = 0;
//扫描待排序数组
for(j = 0;j < n; j++) {
//统计比data[i]值小的值的个数
if(data[j] < data[i]) {
count++;
}
}
if(data[j] < data[i]) {
count++;
}//对于相等非0的数据,应向后措一位。数据为0时,因数组data_p被初始化为0,故不受影响。
while (data_p[count] != 0) {
/* 注意此处应使用while循环进行判断,若用if条件则超过三个重复值后有0出现 */
count++;
}
data_p[count] = data[i];//存放到data_p中的对应位置
}
//用于检查当有多个数相同时的情况
i = 0,j = n;
while(i < j) {
if(data_p[i] == 0) {
temp = i-1;
data_p[i] = data_p[temp];
}//of if
i++;
}//of while
for(i = 0;i < n; i++)//把排序完的数据复制到data中
data[i] = data_p[i];
delete []data_p;//释放data_p
}
假设输入的线性表L的长度为n,L=L1,L2,…,Ln;线性表的元素属于有限偏序集S,|S|=k且k=O(n),S={S1,S2,…Sk};则计数排序可以描述如下:
1、扫描整个集合S,对每一个Si∈S,找到在线性表L中小于等于Si的元素的个数T(Si);
2、扫描整个线性表L,对L中的每一个元素Li,将Li放在输出线性表的第T(Li)个位置上,并将T(Li)减1。
注:在 C++ 中,我们也许经常使用需要建立数组和释放内存的问题,在动态分配内存的时候一般有两种方式,一个是malloc和new两种形式。
比如使用malloc的时候,一般形式如下:
har *Ptr = NULL;
Ptr = (char *)malloc(100 * sizeof(char));
if (NULL == Ptr) {
exit (1);
}
gets(Ptr);
free(Ptr);
在使用new的时候,一般的形式如下:
基数排序的发明可以追溯到1887年赫尔曼·何乐礼在打孔卡片制表机(Tabulation Machine)上的贡献。它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。
/**
* @brief make the all array be sorted by the radix way
* @param arr: the address of the array
* @param len: the length of the array
* @param max: The number of digits of the largest element in the array
*/
void radixSort(int arr[],int len ,int maxDigit) {
int k = 0;
int n = 1;
int m = 1; //控制键值排序为哪一位
int temp[10][len] = {0}; //数组的第一维表示可能的余数0-9
int order[10] = {0};
while (m <= maxDigit) {
for (int i = 0; i < len; i++) {
int lsd = ((arr[i] / n) % 10);
temp[lsd][order[lsd]] = arr[i];
order[lsd]++;
}
for (int i = 0; i < 10; i++){
if (order[i] != 0) {
for (int j = 0; j <order[i]; j++) {
arr[k] = temp[i][j];
k++;
}
order[i] = 0;
}
}
n *= 10;
k = 0;
m++;
}
}
假设数组元素的最高位数N,那么需要迭代N次,直至数组在(个位,十位,百位,千位…)的所有基数上都有序,那么可以认为整个数组是有序的
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
第二步:设定两个下标,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个下标所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一下标超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
void mergeArr(elemType arr[],int low,int mid,int high) {
int *buf = new elemType[high - low + 1];
int i = low;
int j = mid + 1;
int bufIndex = 0;
while ( i <= mid && i <= high) {
if ( nums[i] < nums[j]) {
buf[bufIndex++] = arr[i++];
} else {
buf[bufIndex++] = arr[j++];
}
}
while(i <= mid){
buf[bufIndex++] = arr[i++];
}
while(j <= mid) {
buf[bufIndex++] = arr[j++];
}
for(int k = 0; k < (right - left + 1); k++) {
arr[left+k] = buf[k];
}
delete[] buf;
}
void mergeSort(elemType arr[], int low, int high) {
if (low< high) {
int mid = low+(high- low)/ 2;
mergeSort(arr,low,mid);
mergeSort(arr,mid+1,high);
mergeArr(arr,low,mid,high);
}
}