内排序顾名思义待排序元素总数相对与内存而言较小,整个排序过程可以在内存中进行。反之,如果待排序元素总数较多,不能全部放入内存,排序过程需要访问外存,称之为外排序。内排序算法有序多下面是较常见的几种排序算法:
按照时间复杂度来划分的话,主要有两种:
非线性时间复杂度,下面列举的排序算法的是基于关键字比较和移动两种操作实现的称为“比较排序”,《算法导论》证明过对于任何比较排序在最坏情况下的要Ω(nlgn)次比较来进行排序。
1、简单选择排序算法
2、直接插入排序算法
3、冒泡排序
4、快速排序
5、两路合并排序
6、堆排序
线性时间排序,下面的三种算法的用非比较的一些操作来确定顺序。
1、计数排序
2、基数排序
3、桶排序
另外,排序算法的稳定性是指序列中有关键字值相同元素,排序后原来的相对位置不变。
还有就是原地排序(In place)即在任何时候,数组中只有常数个元素存储在输入数组以外。
下面对于常见的六种比较排序用C++分别实现
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } //简单的冒泡排序算法 /** *冒泡排序思想:对于从小到大排序,第一趟在序列(A[0]~A[n-1])中从前往后进行两个相邻的元素比较,如果后者小 *则交换,比较n-1次。第一趟结束后最大的元素被交换(沉)到底部了。因而下一趟排序只需在子序列(A[0]~A[n-2])中进行! *冒泡排序最多进行n-1趟 *分析:O(n^2) */ template <typename T> void BubbleSortCustom(T *p,int size){ if (size <=1) return ; int i ,j,temp; for(i = 0;i<size;i++) { for(j = 0;j<size-1-i;j++){ if(p[j]>p[j+1]){ Swap(p[j],p[j+1]); } } } } //冒泡排算法改进版 /** *用上面的冒泡排序趟数(n-1)次和第i趟比较次n-i次,的是固定,与初始序列无关 *这应该是最坏的情况,因为有些序列可能没有交换元素,即提前排好序了 *下面的实现最多进行(n-1)趟, *分析:冒泡排序偏爱基于有序的序列 *最好的情况即有序 n-1比较,最坏的进行n-1趟,第i趟比较n-i次。n(n-i)/2 O(n^2); */ template<typename T> void BubbleSort(T *p,int size){ int i,j,last,temp; i = size-1; //最多进行size-1 趟 while(i>0){ last = 0; for(j=0; j<i; j++){ if(p[j]>p[j+1]){ Swap(p[j],p[j+1]); last = j; //如果后面没有交换,说明后面已经排序好了,下一趟只需要比较last次 } } i = last; //如果一趟中没有交换元素last为0结束循环 } } //简单选择排序 /** *在一个子序列中选择一个最小(大)元素与待排序列第一个元素交换 *算法执行时间与初始序列无关 *分析:最好,最坏和平均情况时间复杂度的为O(n^2)a; *不稳定排序 */ template <class T> void SelectSort(T *p,int size){ int small; int i,j,temp; for(i = 0; i< size-1;i++){ small = i; for(j=i+1;j<size;j++ ){ //获取最小元素下标 if(p[j]<p[small]){ small = j ; } } //最小元素与待排序列第一个元素交换 Swap(p[i],p[small]); } } //插入排序 /** *将序列的第一个元素作为一个有序序列,然后将剩下的n-1个元素按照大小 *依次插入到该有序序列,每插入一个元素后依然保持该序列有序 *插入排序可以将有序序列放在新的空间中,不过通常是在原有序列上修改 *分析:直接插入排序必须进行n-1趟,最好的情况下每趟比较1次 *最坏情况下(非递增),第i趟比较i次 复杂度为O(n^2) */ template <typename T> void InsertSort(T *p,int size){ int i,j; for(i = 1;i<size;i++){ T temp = p[i]; //在长度为i的有序序列中查找插入位置 j = i; while(j>0 && temp < p[j-1]){ p[j] = p[j-1]; //p[j-1]元素后移 j--; } //找到插入位置后 p[j] = temp; } } //两路合并排序 /** *将有n个元素的序列看成是n个长度为1的有序子序列,得到n/2(取上)个长度为2或1的有序子序列 *再两两合并,直到得到一个长度为n的有序序列时结束。 */ //合并两个相邻有序子序列,合并后的结果依然是有序的 //q指向n大小的临时内存 template<class T> void Merge(T *p,int i1,int j1,int i2,int j2,T *q){ int i = i1,j = i2,k = 0; while(i<=j1 && j<=j2){ if(p[i] < p[j]) q[k++] = p[i++]; else q[k++] = p[j++]; } //将剩余的放入q中 while(i<=j1) q[k++] = p[i++]; while(j<=j2) q[k++] = p[j++]; //导入到p中 for(i = 0;i<k;i++) p[i1++] = q[i]; } //迭代实现合并排序 template <class T> void MergeSort(T *p,int size){ T *q = new T[size]; //申请一块Size大小的内存 int i1,j1,i2,j2; int num = 1; //确定子序列的边界 while(num < size){ i1 = 0; while(i1+num <size){ i2 = i1+num; j1 = i2-1; if(i2+num>size) j2 = size-1; else j2 = i2+num -1; Merge(p,i1,j1,i2,j2,q); i1 = j2+1;//下一次合并第一个序列的起始 } num *= 2; //元素个数扩大一倍 } delete[] q; } /** * * */ //递归实现快速排序 /** *数组A[p,r] 被分割成两个(可能空)字数组A[p..q-1] 和A[q+1..r]使得A[p,q-1]中的每一个 *元素的小于等于A[q],而且,小于等于A[q+1,r]中的元素,不稳定排序 *快速排序要点在于如何分割序列,下面提供两种方法 */ //第一种分割方法,以A[0]为分割标志 template <class T> void QSort(T *p,int left,int right){ int i,j; if(left<right){ i = left; j = right + 1; do{ do i++; while(p[i]<p[left]); do j--; while(p[j]>p[left]); if(i<j) Swap(p[i],p[j]); }while(i<j); //j为分割点 Swap(p[left],p[j]); QSort(p,left,j-1); QSort(p,j+1,right); } } template <class T> void QuickSort1(T *p,int size){ QSort(p,0,size-1); } //快排第二种分割方法 template <class T> int Partition(T *p,int left,int right){ T x = p[right]; int i = left - 1; int j; for(j=left;j<right;j++){ if(p[j]<=x){ i = i+1; Swap(p[i],p[j]); } } Swap(p[i+1],p[right]); return i+1; } template <class T> void QSort2(T *p,int left ,int right){ if(left<right){ int q = Partition(p,left,right); QSort2(p,left,q-1); QSort2(p,q+1,right); } } template <class T> void QuickSort2(T *p,int size){ QSort2(p,0,size-1); } //堆排序 /** *利用最小堆或者是最大堆来实现排序,时间复杂度为nlgn *堆排序和插入排序一样,是一种原地(in place)排序算法 *二叉堆数据结构是一种数组对象,是数组抽象出来的。 *对于完全二叉树,数组的第i节点的父节点为i/2 左子节点 2i,右子节点2i+1 *最大堆是父不小于子,最小堆是父不大于子 */ //保持堆的性质 //对于最大堆,插入一个节点时,其左右子树的是最大堆。为了保证插入新节点后依然能够保持 //最大堆的性质,就需要调整堆 template <class T> void MaxHeapIFY(T *p,int i, int heapsize){ int l = i<<1; //左子 int r = (i<<1)+1;//右子 int largest = 0; if(l<heapsize && p[l]>p[i]) largest = l; else largest = i; if(r<heapsize && p[r]>p[largest]) largest = r; if(largest != i){ Swap(p[i],p[largest]); MaxHeapIFY(p,largest,heapsize); } } //建堆排序 //堆排序通过删堆来实现,从根节点来删除,将要删除的根节点(A[0])与堆的最后一个元素(A[n-1])互换 //然后删除堆的尾部即减小堆的大小为n-1,然后再从新调整i=0节点 ,保持堆的性质。 template <class T> void HeapSort(T *p,int size){ //建最大堆 for(int i=size/2; i>=1;i--){ MaxHeapIFY(p,i,size); } //排序 int heapsize = size; for(int j = size-1;j>0;j--){ Swap(p[0],p[j]); heapsize = heapsize -1; MaxHeapIFY (p,0,heapsize); } } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; // InsertSort(a,8); //SelectSort(a,8); //MergeSort(a,8); //QuickSort2(a,8); HeapSort(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; } #include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } //简单的冒泡排序算法 /** *冒泡排序思想:对于从小到大排序,第一趟在序列(A[0]~A[n-1])中从前往后进行两个相邻都元素比较,如果后者小 *则交换,比较n-1次。第一趟结束后最大都元素被交换(沉)到底部了。因而下一趟排序只需在子序列(A[0]~A[n-2])中进行! *冒泡排序最多进行n-1趟 *分析:O(n^2) */ template <typename T> void BubbleSortCustom(T *p,int size){ if (size <=1) return ; int i ,j,temp; for(i = 0;i<size;i++) { for(j = 0;j<size-1-i;j++){ if(p[j]>p[j+1]){ Swap(p[j],p[j+1]); } } } } //冒泡排算法改进版 /** *用上面的冒泡排序趟数(n-1)次和第i趟比较次n-i次,都是固定,与初始序列无关 *这应该是最坏的情况,因为有些序列可能没有交换元素,即提前排好序了 *下面的实现最多进行(n-1)趟, *分析:冒泡排序偏爱基于有序都序列 *最好的情况即有序 n-1比较,最坏都进行n-1趟,第i趟比较n-i次。n(n-i)/2 O(n^2); */ template<typename T> void BubbleSort(T *p,int size){ int i,j,last,temp; i = size-1; //最多进行size-1 趟 while(i>0){ last = 0; for(j=0; j<i; j++){ if(p[j]>p[j+1]){ Swap(p[j],p[j+1]); last = j; //如果后面没有交换,说明后面已经排序好了,下一趟只需要比较last次 } } i = last; //如果一趟中没有交换元素last为0结束循环 } } //简单选择排序 /** *在一个子序列中选择一个最小(大)元素与待排序列第一个元素交换 *算法执行时间与初始序列无关 *分析:最好,最坏和平均情况时间复杂度都为O(n^2)a; *不稳定排序 */ template <class T> void SelectSort(T *p,int size){ int small; int i,j,temp; for(i = 0; i< size-1;i++){ small = i; for(j=i+1;j<size;j++ ){ //获取最小元素下标 if(p[j]<p[small]){ small = j ; } } //最小元素与待排序列第一个元素交换 Swap(p[i],p[small]); } } //插入排序 /** *将序列都第一个元素作为一个有序序列,然后将剩下都n-1个元素按照大小 *依次插入到该有序序列,每插入一个元素后依然保持该序列有序 *插入排序可以将有序序列放在新都空间中,不过通常是在原有序列上修改 *分析:直接插入排序必须进行n-1趟,最好都情况下每趟比较1次 *最坏情况下(非递增),第i趟比较i次 复杂度为O(n^2) */ template <typename T> void InsertSort(T *p,int size){ int i,j; for(i = 1;i<size;i++){ T temp = p[i]; //在长度为i都有序序列中查找插入位置 j = i; while(j>0 && temp < p[j-1]){ p[j] = p[j-1]; //p[j-1]元素后移 j--; } //找到插入位置后 p[j] = temp; } } //两路合并排序 /** *将有n个元素都序列看成是n个长度为1的有序子序列,得到n/2(取上)个长度为2或1的有序子序列 *再两两合并,直到得到一个长度为n的有序序列时结束。 */ //合并两个相邻有序子序列,合并后都结果依然是有序的 //q指向n大小都临时内存 template<class T> void Merge(T *p,int i1,int j1,int i2,int j2,T *q){ int i = i1,j = i2,k = 0; while(i<=j1 && j<=j2){ if(p[i] < p[j]) q[k++] = p[i++]; else q[k++] = p[j++]; } //将剩余都放入q中 while(i<=j1) q[k++] = p[i++]; while(j<=j2) q[k++] = p[j++]; //导入到p中 for(i = 0;i<k;i++) p[i1++] = q[i]; } //迭代实现合并排序 template <class T> void MergeSort(T *p,int size){ T *q = new T[size]; //申请一块Size大小都内存 int i1,j1,i2,j2; int num = 1; //确定子序列都边界 while(num < size){ i1 = 0; while(i1+num <size){ i2 = i1+num; j1 = i2-1; if(i2+num>size) j2 = size-1; else j2 = i2+num -1; Merge(p,i1,j1,i2,j2,q); i1 = j2+1;//下一次合并第一个序列都起始 } num *= 2; //元素个数扩大一倍 } delete[] q; /** * * */ //递归实现快速排序 /** *数组A[p,r] 被分割成两个(可能空)字数组A[p..q-1] 和A[q+1..r]使得A[p,q-1]中的每一个 *元素都小于等于A[q],而且,小于等于A[q+1,r]中的元素,不稳定排序 *快速排序要点在于如何分割序列,下面提供两种方法 */ //第一种分割方法,以A[0]为分割标志 template <class T> void QSort(T *p,int left,int right){ int i,j; if(left<right){ i = left; j = right + 1; do{ do i++; while(p[i]<p[left]); do j--; while(p[j]>p[left]); if(i<j) Swap(p[i],p[j]); }while(i<j); //j为分割点 Swap(p[left],p[j]); QSort(p,left,j-1); QSort(p,j+1,right); } } template <class T> void QuickSort1(T *p,int size){ QSort(p,0,size-1); } //快排第二种分割方法 template <class T> int Partition(T *p,int left,int right){ T x = p[right]; int i = left - 1; int j; for(j=left;j<right;j++){ if(p[j]<=x){ i = i+1; Swap(p[i],p[j]); } } Swap(p[i+1],p[right]); return i+1; } template <class T> void QSort2(T *p,int left ,int right){ if(left<right){ int q = Partition(p,left,right); QSort2(p,left,q-1); QSort2(p,q+1,right); } } template <class T> void QuickSort2(T *p,int size){ QSort2(p,0,size-1); } //堆排序 /** *利用最小堆或者是最大堆来实现排序,时间复杂度为nlgn *堆排序和插入排序一样,是一种原地(in place)排序算法 *二叉堆数据结构是一种数组对象,是数组抽象出来的。 *对于完全二叉树,数组都第i节点都父节点为i/2 左子节点 2i,右子节点2i+1 *最大堆是父不小于子,最小堆是父不大于子 */ int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; int *p = NULL; // BubbleSort(p,0); // InsertSort(a,8); // cout<<x<<" "<<y <<endl; //SelectSort(a,8); //MergeSort(a,8); QuickSort2(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
总结分析
对于上面已经实现的几种比较排序算法总结如下:
简单选择排序: 算法执行时间与初始序列无关,最好、最坏、平均时间复杂度的为O(n^2),是不稳定排序方法
直接插入排序:与初始序列排列有关,最好的情况下(顺序)时间复杂度为O(n),最坏(反序)是O(n^2)
冒泡排序 :最好是O(n),最坏O(n^2)
快速排序 : 快速排序适合元素多的情形,偏爱无序的序列,分割元素的选择直接会影响到快排的效率,如果每一层递归上做的划分的是最坏的划分,时间复杂度为O(n^2),平均情况下快排的时间复杂度为O(nlgn),快速排序适用与已知第K(k比较小)个小元素A在表中的位置,要尽可能短的时间内在较多的元素中找出前K个小元素,且找出的元素需要按照非递减排列,这样可以用A作为分割元素进行一趟快速排序即可划分出前k个元素了,然后简单排序即可。
两路合并排序,不是原地排序,却是稳定排序,额外的空间复杂度为O(n) ,时间复杂度为O(nlgn)与初始序列无关。
堆排序: 对排序是原地排序,不稳定排序,时间复杂度为O(nlgn),建堆时间为O(n),排序n-1次调整代价为O(lgn).
1===//简单的冒泡排序算法
/**
*冒泡排序思想:对于从小到大排序,第一趟在序列(A[0]~A[n-1])中从前往后进行两个相邻的元素比较,如果后者小
*则交换,比较n-1次。第一趟结束后最大的元素被交换(沉)到底部了。因而下一趟排序只需在子序列(A[0]~A[n-2])中进行!
*冒泡排序最多进行n-1趟
*分析:O(n^2)
*/
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } template <typename T> void BubbleSortCustom(T *p,int size){ if (size <=1) return ; int i ,j,temp; for(i = 0;i<size;i++) { for(j = 0;j<size-1-i;j++){ if(p[j]>p[j+1]){ Swap(p[j],p[j+1]); } } } } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; BubbleSortCustom(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
2===//冒泡排算法改进版
/**
*用上面的冒泡排序趟数(n-1)次和第i趟比较次n-i次,的是固定,与初始序列无关
*这应该是最坏的情况,因为有些序列可能没有交换元素,即提前排好序了
*下面的实现最多进行(n-1)趟,
*分析:冒泡排序偏爱基于有序的序列
*最好的情况即有序 n-1比较,最坏的进行n-1趟,第i趟比较n-i次。n(n-i)/2 O(n^2);
*/
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } template<typename T> void BubbleSort(T *p,int size){ int i,j,last,temp; i = size-1; //最多进行size-1 趟 while(i>0){ last = 0; for(j=0; j<i; j++){ if(p[j]>p[j+1]){ Swap(p[j],p[j+1]); last = j; //如果后面没有交换,说明后面已经排序好了,下一趟只需要比较last次 } } i = last; //如果一趟中没有交换元素last为0结束循环 } } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; BubbleSort(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
3===//简单选择排序
/**
*在一个子序列中选择一个最小(大)元素与待排序列第一个元素交换
*算法执行时间与初始序列无关
*分析:最好,最坏和平均情况时间复杂度的为O(n^2)a;
*不稳定排序
*/
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } template <class T> void SelectSort(T *p,int size){ int small; int i,j,temp; for(i = 0; i< size-1;i++){ small = i; for(j=i+1;j<size;j++ ){ //获取最小元素下标 if(p[j]<p[small]){ small = j ; } } //最小元素与待排序列第一个元素交换 Swap(p[i],p[small]); } } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; SelectSort(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
4===//插入排序
/**
*将序列的第一个元素作为一个有序序列,然后将剩下的n-1个元素按照大小
*依次插入到该有序序列,每插入一个元素后依然保持该序列有序
*插入排序可以将有序序列放在新的空间中,不过通常是在原有序列上修改
*分析:直接插入排序必须进行n-1趟,最好的情况下每趟比较1次
*最坏情况下(非递增),第i趟比较i次 复杂度为O(n^2)
*/
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } template <typename T> void InsertSort(T *p,int size){ int i,j; for(i = 1;i<size;i++){ T temp = p[i]; //在长度为i的有序序列中查找插入位置 j = i; while(j>0 && temp < p[j-1]){ p[j] = p[j-1]; //p[j-1]元素后移 j--; } //找到插入位置后 p[j] = temp; } } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; InsertSort(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
5===//两路合并排序
/**
*将有n个元素的序列看成是n个长度为1的有序子序列,得到n/2(取上)个长度为2或1的有序子序列
*再两两合并,直到得到一个长度为n的有序序列时结束。
*/
//合并两个相邻有序子序列,合并后的结果依然是有序的
//q指向n大小的临时内存
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } template<class T> void Merge(T *p,int i1,int j1,int i2,int j2,T *q){ int i = i1,j = i2,k = 0; while(i<=j1 && j<=j2){ if(p[i] < p[j]) q[k++] = p[i++]; else q[k++] = p[j++]; } //将剩余的放入q中 while(i<=j1) q[k++] = p[i++]; while(j<=j2) q[k++] = p[j++]; //导入到p中 for(i = 0;i<k;i++) p[i1++] = q[i]; } //迭代实现合并排序 template <class T> void MergeSort(T *p,int size){ T *q = new T[size]; //申请一块Size大小的内存 int i1,j1,i2,j2; int num = 1; //确定子序列的边界 while(num < size){ i1 = 0; while(i1+num <size){ i2 = i1+num; j1 = i2-1; if(i2+num>size) j2 = size-1; else j2 = i2+num -1; Merge(p,i1,j1,i2,j2,q); i1 = j2+1;//下一次合并第一个序列的起始 } num *= 2; //元素个数扩大一倍 } delete[] q; } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; MergeSort(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
6==/**
*
*
*/
//递归实现快速排序
/**
*数组A[p,r] 被分割成两个(可能空)字数组A[p..q-1] 和A[q+1..r]使得A[p,q-1]中的每一个
*元素的小于等于A[q],而且,小于等于A[q+1,r]中的元素,不稳定排序
*快速排序要点在于如何分割序列,下面提供两种方法
*/
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } //第一种分割方法,以A[0]为分割标志 template <class T> void QSort(T *p,int left,int right){ int i,j; if(left<right){ i = left; j = right + 1; do{ do i++; while(p[i]<p[left]); do j--; while(p[j]>p[left]); if(i<j) Swap(p[i],p[j]); }while(i<j); //j为分割点 Swap(p[left],p[j]); QSort(p,left,j-1); QSort(p,j+1,right); } } template <class T> void QuickSort1(T *p,int size){ QSort(p,0,size-1); } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; QuickSort1(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } //快排第二种分割方法 template <class T> int Partition(T *p,int left,int right){ T x = p[right]; int i = left - 1; int j; for(j=left;j<right;j++){ if(p[j]<=x){ i = i+1; Swap(p[i],p[j]); } } Swap(p[i+1],p[right]); return i+1; } template <class T> void QSort2(T *p,int left ,int right){ if(left<right){ int q = Partition(p,left,right); QSort2(p,left,q-1); QSort2(p,q+1,right); } } template <class T> void QuickSort2(T *p,int size){ QSort2(p,0,size-1); } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; QuickSort2(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
7==//堆排序
/**
*利用最小堆或者是最大堆来实现排序,时间复杂度为nlgn
*堆排序和插入排序一样,是一种原地(in place)排序算法
*二叉堆数据结构是一种数组对象,是数组抽象出来的。
*对于完全二叉树,数组的第i节点的父节点为i/2 左子节点 2i,右子节点2i+1
*最大堆是父不小于子,最小堆是父不大于子
*/
//保持堆的性质
//对于最大堆,插入一个节点时,其左右子树的是最大堆。为了保证插入新节点后依然能够保持
//最大堆的性质,就需要调整堆
#include<iostream> #include<string.h> #include<memory.h> using namespace std; template <class T> inline void Swap(T &a,T &b){ T temp = a; a = b; b = temp; } template <class T> void MaxHeapIFY(T *p,int i, int heapsize){ int l = i<<1; //左子 int r = (i<<1)+1;//右子 int largest = 0; if(l<heapsize && p[l]>p[i]) largest = l; else largest = i; if(r<heapsize && p[r]>p[largest]) largest = r; if(largest != i){ Swap(p[i],p[largest]); MaxHeapIFY(p,largest,heapsize); } } //建堆排序 //堆排序通过删堆来实现,从根节点来删除,将要删除的根节点(A[0])与堆的最后一个元素(A[n-1])互换 //然后删除堆的尾部即减小堆的大小为n-1,然后再从新调整i=0节点 ,保持堆的性质。 template <class T> void HeapSort(T *p,int size){ //建最大堆 for(int i=size/2; i>=1;i--){ MaxHeapIFY(p,i,size); } //排序 int heapsize = size; for(int j = size-1;j>0;j--){ Swap(p[0],p[j]); heapsize = heapsize -1; MaxHeapIFY (p,0,heapsize); } } int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; HeapSort(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }
int main(){ double a[] = { 29,18,9,12,10,23,4,5.3}; int *p = NULL;///////////////////////////////////////////////////////////////// // BubbleSort(p,0); // InsertSort(a,8); // cout<<x<<" "<<y <<endl; //SelectSort(a,8); //MergeSort(a,8); //HeapSort(a,8); for(int i =0;i<8;i++) cout<<a[i]<<" "; cout<<endl; return 0; }