作者:王为涛
最近无聊时,就想起来大学想做的个哈希排序算法,就又按哈希的思想做了个优化版的排序算法,请大家指教。
注: 写的时候没有参考其他的排序算法,如果有意外和某些已发表的算法重和的话,还请告知,我做描述修改。
算法步骤:
1. 使用二进制1000 0000 0000 0000 作为第一层的哈希函数,与数组中的数做&操作,将数组分成大数组和小数组,覆盖到原始数组中,并保存各自的开始和结束的下标,供下层递归做循环范围使用。
2. 将哈希函数右移1位,和起止范围送入下一层递归中,重复上步骤的操作,将小数组中再分为一个大数组和小数组,继续递归,直到哈希函数为1或者待递归的范围为1了。
3.递归结束后,原始数组中数字就有序了。
稳定性:
排序时,小数组会从左到右插入数据,可以保持稳定性,大数组从右到左插入数据,如果需要保持稳定性的话,可以将大数组写入原始数组时从右向左遍历插入,可以保持稳定性。
下面的演示程序没有保持稳定性。
算法性能:
算法的时间复杂度是 <O(16n),因为很多大小数组分到最后可能只有一个数了,就不往下分了,会减少递归的层数,递归的层数是根据排序的变量类型和范围决定的,我这里用的0-32760间的数字,所以使用了16位的哈希函数,如果是32位的数字就需要32n的时间复杂度了。
算法的空间复杂度是O(n),使用了n个长度的临时空间做缓存,然后单线程递归时,只保留了16个现场,其中使用的临时变量较少,加上环境压栈所占也很小。同时,可以很容易的将递归操作改成16层的循环操作,可以节省环境压栈所用的空间。
多线程优化:
如果电脑性能较好,多线程能力十分强劲,在第一层递归时,直接使用多线程执行两条分支,这样到最下面一层会产生2的16次方的线程数,很久没用c语言了,线程方面的东西基本忘干净了,了解的网友可以说下。
if(start<n)
fun(p,q,start,n,tempn);
if(m<end)
fun(p,q,m+1,end,tempn);
大量数据分块排序:
如果数据量十分巨大,可以每次读取一定数据,然后写入硬盘中,然后下次递归重新读取硬盘中的数据,直到满足空间可容纳的时候,可以在内存中进行排序,然后将结果写入硬盘。
[code=c]#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX 1000000
void fun(int *p,int *q,int start,int end , int hashn){
int n=start;
int m=end-1;
int i;
for(i=start;i<end;i++){
if((p[i]&hashn) == 0){
q[n++] = p[i];
}else {
q[m--] = p[i];
}
}
for(i=start;i<end;i++){
p[i]= q[i];
}
if(hashn == 1){
return ;
} else {
int tempn = hashn >>1;
if(start<n)
fun(p,q,start,n,tempn);
if(m<end)
fun(p,q,m+1,end,tempn);
}
}
void main(){
unsigned int arr[MAX];
unsigned int temp[MAX];
clock_t startt,finish;
unsigned int hashn = 0x8000;
srand(time(0));
int i;
printf("开始随机生成数组%ld\n",clock());
for(i=0;i<MAX;i++){
arr[i]= rand()&32760;
}
printf("结束随即生成数组%ld\n",clock());
startt = clock();
fun(arr,temp,0,MAX,hashn);
finish = clock();
printf("执行时长%f\n",(double)(finish-startt)/CLOCKS_PER_SEC);
}
[/code]
转载请附上此地址
最近无聊时,就想起来大学想做的个哈希排序算法,就又按哈希的思想做了个优化版的排序算法,请大家指教。
注: 写的时候没有参考其他的排序算法,如果有意外和某些已发表的算法重和的话,还请告知,我做描述修改。
算法步骤:
1. 使用二进制1000 0000 0000 0000 作为第一层的哈希函数,与数组中的数做&操作,将数组分成大数组和小数组,覆盖到原始数组中,并保存各自的开始和结束的下标,供下层递归做循环范围使用。
2. 将哈希函数右移1位,和起止范围送入下一层递归中,重复上步骤的操作,将小数组中再分为一个大数组和小数组,继续递归,直到哈希函数为1或者待递归的范围为1了。
3.递归结束后,原始数组中数字就有序了。
稳定性:
排序时,小数组会从左到右插入数据,可以保持稳定性,大数组从右到左插入数据,如果需要保持稳定性的话,可以将大数组写入原始数组时从右向左遍历插入,可以保持稳定性。
下面的演示程序没有保持稳定性。
算法性能:
算法的时间复杂度是 <O(16n),因为很多大小数组分到最后可能只有一个数了,就不往下分了,会减少递归的层数,递归的层数是根据排序的变量类型和范围决定的,我这里用的0-32760间的数字,所以使用了16位的哈希函数,如果是32位的数字就需要32n的时间复杂度了。
算法的空间复杂度是O(n),使用了n个长度的临时空间做缓存,然后单线程递归时,只保留了16个现场,其中使用的临时变量较少,加上环境压栈所占也很小。同时,可以很容易的将递归操作改成16层的循环操作,可以节省环境压栈所用的空间。
多线程优化:
如果电脑性能较好,多线程能力十分强劲,在第一层递归时,直接使用多线程执行两条分支,这样到最下面一层会产生2的16次方的线程数,很久没用c语言了,线程方面的东西基本忘干净了,了解的网友可以说下。
if(start<n)
fun(p,q,start,n,tempn);
if(m<end)
fun(p,q,m+1,end,tempn);
大量数据分块排序:
如果数据量十分巨大,可以每次读取一定数据,然后写入硬盘中,然后下次递归重新读取硬盘中的数据,直到满足空间可容纳的时候,可以在内存中进行排序,然后将结果写入硬盘。
[code=c]#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX 1000000
void fun(int *p,int *q,int start,int end , int hashn){
int n=start;
int m=end-1;
int i;
for(i=start;i<end;i++){
if((p[i]&hashn) == 0){
q[n++] = p[i];
}else {
q[m--] = p[i];
}
}
for(i=start;i<end;i++){
p[i]= q[i];
}
if(hashn == 1){
return ;
} else {
int tempn = hashn >>1;
if(start<n)
fun(p,q,start,n,tempn);
if(m<end)
fun(p,q,m+1,end,tempn);
}
}
void main(){
unsigned int arr[MAX];
unsigned int temp[MAX];
clock_t startt,finish;
unsigned int hashn = 0x8000;
srand(time(0));
int i;
printf("开始随机生成数组%ld\n",clock());
for(i=0;i<MAX;i++){
arr[i]= rand()&32760;
}
printf("结束随即生成数组%ld\n",clock());
startt = clock();
fun(arr,temp,0,MAX,hashn);
finish = clock();
printf("执行时长%f\n",(double)(finish-startt)/CLOCKS_PER_SEC);
}
[/code]
转载请附上此地址
本文介绍了一种基于哈希思想的优化排序算法,采用递归方式将数组中的元素按大小分为两个子数组,直至完成排序。该算法的时间复杂度小于O(16n),空间复杂度为O(n)。
排序算法用到二叉树和哈希思想,多线程优化和大量数据分块排序都很好弄&spm=1001.2101.3001.5002&articleId=79936294&d=1&t=3&u=22b3e744b90c45a98e3e9cc35ac10ca5)

被折叠的 条评论
为什么被折叠?



