标签:make down 有序 class for 完全二叉树 递归 时间 article
本篇文章总结一下最近学习的排序算法,提炼出其思想及不同之处。有归并排序,快速排序,堆排序以及冒泡排序
采用两两分解和归并的策略简单易行,这样的归并排序称为2-路归并排序。
public static void sort(int[] arr) {
if (arr == null || arr.length == 0)
return;
int len = arr.length;
int[] temp = new int[len];
mergeSort(arr, 0, len - 1, temp);
}
public static void mergeSort(int[] arr, int first, int last, int[] temp) {
// 条件
if (first < last) {
int mid = (first + last) / 2;
mergeSort(arr, first, mid, temp);
mergeSort(arr, mid + 1, last, temp);
mergeArray(arr, first, mid, last, temp);
}
}
public static void mergeArray(int[] arr, int first, int mid, int last, int[] temp) {
int i = first, j = mid + 1;
int index = first;
while (i <= mid && j <= last) {
// 排序条件
if (arr[i] > arr[j])
temp[index++] = arr[i++];
else
temp[index++] = arr[j++];
}
while (i <= mid)
temp[index++] = arr[i++];
while (j <= last)
temp[index++] = arr[j++];
for (int k = first; k <= last; k++) {
arr[k] = temp[k];
}
}
另一种写法:
// 将相邻有序的a[i..m]和a[m+1..n] 归并到b[i..n] 包含 n
void Merge(int a[], int i,int m, int n, int b[]){
int k,j;
for(k = i, j = m+1; k <= m && j <= n;k++){
if(a[i] < a[j]){
b[k] = a[i++];
}else{
b[k] = a[j++];
}
}
while(i<=m) b[k++] = a[i++];
while(j<=n) b[k++] = a[j++];
}
// i:递归的层次(第一层为0)-- 用于指示在MSort当前调用层次中a,b数组的具体作用:
// 当i为奇数时,则从a[s..t]归并至b[s..t]
// 否则从b[s..t]归并至a[s..t]
void MSort(int a[], int b[], int i,int s,int t){
int m;
if( s == t ){
if( 1 == i%2 ) b[s] = a[s];
}else{
m = (s+t)/2;
MSort(a,b,i+1,s,m);
MSort(a,b,i+1,m+1,t);
if( 1 == i%2 ) Merge(a,s,m,t,b);
else Merge(b,s,m,t,a);
}
}
void MergeSort(int a[],int len){
int b[len];
MSort(a,b,0,0,len-1);
free(b); // 释放资源
}
简单分析:
整个归并排序过程需要进行
归并排序是稳定排序
最简单的交换排序是冒泡排序,而快速排序是对冒泡排序的改进。
首先从待排序列中选定一个关键字,称为枢轴,通过关键字与枢轴的比较将待排序的序列划分为位于枢轴前后的两个子序列,其中枢轴之前的子序列的所有关键字都不大于枢轴,枢轴之后的子序列都不小于枢轴,此时枢轴已经到位,再按同样的方法对这两个子序列分别递归进行快速排序,最终使得整个序列有序
快速排序的一次划分具体过程:
private static void qSort(int[] arr) {
if (arr == null || arr.length == 0)
return;
qSort(arr, 0, arr.length - 1);
}
public static void qSort(int[] arr, int first, int last) {
// 长度大于一
if (first < last) {
int pKey = partition(arr, first, last);
// 记得pKey位置已经不用再参与了,所以pKey - 1 和 pKey + 1
qSort(arr, first, pKey - 1);
qSort(arr, pKey + 1, last);
System.out.println("key : " + pKey);
} else {
System.out.println("first > last");
}
}
public static int partition(int[] arr, int first, int last) {
int key = arr[first];
while (first < last) {
// 注意这里的>= 和 <=
while (first < last && arr[last] >= key)
last--;
arr[first] = arr[last];
while (first < last && arr[first] <= key)
first++;
arr[last] = arr[first];
}
arr[first] = key;
return first;
}
为避免枢轴关键字为最大或者最小的情况,可采用“三者取中”的方法,即以a[s]、a[t]、a[(s+t)/2]三者中关键字的大小居中的记录为枢轴,并与a[s]互换
堆是一类完全二叉树,若堆中所有非叶子结点均不大于其左右子节点,则称为小顶堆;若堆中所有非叶子结点均不小于其左右子节点,则称为大顶堆
堆的结构类型
typedef struct{
int *rcd; // 堆基址,0号但愿不可用
int n; // 堆长度
int size; // 堆容器
int tag; // 小顶堆和大顶堆的标志
int (*prior)(int a,int b); // 函数变量,用于关键字优先级比较
} Heap;
int greatPrior(int x,int y) { return x>=y; }
int lessPrior(int x,int y) { return x<=y; }
int SwapHeapElem(Heap &H,int i, int j){
if( i < 0 || i > H.n || j < 0 || j > H.n ) return 0;
int t;
t = H.rcd[i];
H.rcd[i] = H.rcd[j];
H.rcd[j] = t;
return 1;
}
// 堆的筛选操作,对堆中指定的pos结点为根的子树进行堆的特性的维护,其前提是pos结点的左右子树均满足堆特性
void ShiftDown(Heap &H,int pos){
int c, rc;
while(pos<=H.n/2){
c = pos*2;
rc = pos*2+1;
if(rc<=H.n && H.prior(H.rcd[rc],H.rcd[c])) c = rc; // 这里注意函数的比较元素位置
if(H.prior(H.rcd[pos],H.rcd[c]))
return ;
SwapHeapElem(H,pos,c);
pos = c;
}
}
int RemoveFirsHeap(Heap &H, int &e){
if(H.n<=0) return 0;
e = H.rcd[1];
SwapHeapElem(H,1,H.n);
if(H.n>1) ShiftDown(H,1);
return 1;
}
void MakeHeap(Heap &H,int a[],int n,int size,int tag,int (*prior)(int a,int b)){
H.rcd = a;
H.n = n;
H.size = size;
H.tag = tag;
H.prior = prior;
int i;
// 叶子结点满足堆特性,故不需要筛选
for( i = H.n/2; i > 0; i -- ){
ShiftDown(H,i);
}
}
void HeapSort(int a[],int n){
Heap H;
MakeHeap(H,a,n,n+2,1,lessPrior);
int e;
for( int i = H.n; i > 0; i -- ){
if(RemoveFirsHeap(H,e) )
printf("%d ",e);
}
}
void BubbleSort(int a[], int len){
int t;
int i, j;
// i表示已经排序的个数
for( i = 0; i < len; i ++ ){
// 开始冒泡到len-i,len-i之后表示已经达到最值
for( j = 1; j < len-i; j ++ ){
if( a[j-1] < a[j] ){
t = a[j-1];
a[j-1] = a[j];
a[j] = t;
}
}
}
}
改进:
void BubbleSort(int a[], int len){
int t;
int i, j, flag;
flag = -1;
// i表示已经排到序的个数,(及排到最尾端的个数)
// flag表示a[flag-1,flag..len-1]已经为有序序列,所以flag之后的为不用再排序序列
for( i = 0; i < len; i ++ ){
if( flag != -1 ){
i = len - flag; // 表示 已经排到序的个数
flag = -1;
}
for( j = 1; j < len-i; j ++ ){
if( a[j-1] > a[j] ){
flag = j;
t = a[j-1];
a[j-1] = a[j];
a[j] = t;
}
}
}
}
其他学习链接冒泡排序的三种实现
标签:make down 有序 class for 完全二叉树 递归 时间 article
原文地址:http://blog.csdn.net/y_zhiwen/article/details/50057813