数据结构
这里我不采用数组来进行排序,而是采用更加符合应用的数据结构来排序。
#define M 100
typedef int datatype;
typedef struct node{
datatype r[M+1];
int lengh;
}table;
这是一种简单描述,更加详细的数据机构应该是下面这样(但是为了方便描述还是使用上面的简单结构):
#define M 100
typedef int datatype;
typedef struct {
datatype key;
//其他数据...
}sort_record;
typedef struct node{
sort_record r[M+1];
int lengh;
}table;
说明:这里不考虑程序的鲁棒性,对于略去了对参数的检查,只为了更加清晰地描述算法,本来想用数组的但是觉得使用结构体更加合乎实际应用逻辑。每种算法都是必须非常熟练的,至于思路就不用说了读代码就行
注意:数组中第一个元素tab[0]都是拿来作为哨兵元素的。默认升序排序。
插入排序
1. 直接插入排序
//1.直接插入
void direct_insert_sort(table* tab)
{
int i,j;
for (i = 1;i<tab->lengh;i++)
{
j = i-1;
tab->r[0] = tab->r[i];
while(tab->r[0] < tab->r[j])
{
tab->r[j+1] = tab->r[j];
j = j-1;
}
tab->r[j+1] = tab->r[0];
}
}
2. 二分插入排序
当某些元素是有序的时候,利用二分查找,找到插入的位置,然后插入位置后面的元素后移一位。
void binary_insert_sort(table* tab)
{
int i,j,left,right,mid;
for(i =1;i<tab->lengh;i++)
{
left = 1;right = i-1;
tab->r[0] = tab->r[i];
while(left <= right)
{
mid = (left + right) /2;
if (tab->r[mid] > tab->r[0]){
right = mid -1;
}
else{
left = mid+1;
}
}
for (j=i-1;j>=left;j--)
{
tab->r[j+1] = tab->r[j];
}
tab->r[left] = tab->r[0];
}
}
3. 希尔插入排序
void shell_sort(table* tab)
{
int i,j,gap;
gap = tab->lengh / 2;
while(gap >= 1)
{
for (i = 1+gap;i<=tab->lengh;i++)
{
j = i -gap;
tab->r[0] = tab->r[i];
while(tab->r[0] < tab->r[j] && j>0)
{
tab->r[j+gap] = tab->r[j];
j = j-gap;
}
tab->r[j +gap] = tab->r[0];
}
gap = gap/2;
}
}
交换排序
4. 冒泡排序
//4.冒泡排序
void bubble_sort(table* tab)
{
int i,j,done;
done = 1;
for(i = 1;i<= tab->lengh&&done;i++)
{
done = 0;
for (j = 1;j<= tab->lengh - i;j++)
{
if (tab->r[j] > tab->r[j+1])
{
swap(tab->r[j],tab->r[j+1]);
done = 1;
}
}
}
}
5. 快速排序
//5.快速排序
void quick_sort(table* tab,int left,int right)
{
if (left >= right)
return;
int i,j;
i = left;j = right;
tab->r[0] = tab->r[i];
while(i < j)
{
while(tab->r[i] <= tab->r[j]&&i<j)
j--;
if (i<j){
tab->r[i] = tab->r[j];
i++;
}
while(tab->r[j] >= tab->r[i]&&i<j)
i++;
if (i<j){
tab->r[j] = tab->r[i];
j--;
}
}
tab->r[i] = tab->r[0];
quick_sort(tab,left,i-1);
quick_sort(tab,i+1,right);
}
选择排序
6. 直接选择排序
//6.直接选择
void direct_select_sort(table* tab)
{
int i,j,k;
for (i =1;i<=tab->lengh;i++)
{
k = i;
for(j = i+1;j<=tab->lengh;j++)
{
if (tab->r[k] > tab->r[j])
k = j;
}
if (k != i)
{
swap(tab->r[k],tab->r[i]);
}
}
}
7. 堆排序
//7.堆排序
//index表示要调整的节点的下标,n表示堆元素个数。
void shift_heap(table* tab,int index,int n)
{
int i,j,finished = 0;
tab->r[0] = tab->r[index];
i = index; j = 2*i;
while(j<=n && !finished)
{
if (tab->r[j] > tab->r[j+1]&&j<=n)
j++;
if (tab->r[0] <= tab->r[j])
{
finished = 1;
}
else
{
tab->r[i] = tab->r[j];
i = j;
j = 2*i;
}
}
tab->r[i] = tab->r[0];
}
void heap_sort(table* tab)
{
int i;
for (i = tab->lengh/2;i>=1;i--)
{
shift_heap(tab,i,tab->lengh);
}
for (int i = 2;i<tab->lengh;i++)
{
shift_heap(tab,i,tab->lengh);
}
}
8. 归并排序
//8.归并排序
//将tabs中的u-m-v的元素合并到tabg中
void merge(table* tabs,table* tabg,int u,int m,int v)
{
int i,j,k,t;
i = u; j = m +1;
k = u;
while(i<=m && j <= v)
{
if (tabs->r[i] < tabs->r[j])
{
tabg->r[k++] = tabs->r[i];
i++;
}
else
{
tabg->r[k++] = tabs->r[j];
j++;
}
}
if (i<=m)
{
for(t = i;t<=m;t++)
tabg->r[k++] = tabs->r[t];
}
else
{
for(t = i;t<=v;t++)
tabg->r[k++] = tabs->r[t];
}
}
//递归实现
void merge_sort1(table* tabs,table* tabg,int left,int right)
{
if (left>= right)
{
return;
}
int mid = (left+right)/2;
merge_sort1(tabs,tabg,left,mid);
merge_sort1(tabs,tabg,mid+1,right);
merge(tabs,tabg,left,mid,right);
}
//非递归实现
void merge_pass(table* tabs,table* tabg,int len)
{
int i,j,n;
tabg->lengh = n = tabs->lengh;
for(i =1;i<n-2*len+1;i+=2*len)
{
merge(tabs,tabg,i,i+len-1,i+2*len-1);
}
if (i+len-1<n){
merge(tabs,tabg,i,i+len-1,n);
}
else{
for(j=i;j<=n;j++){
tabg->r[j] = tabs->r[j];
}
}
}
void merge_sort(table* tab)
{
int len;
table tmp;
len =1;
while(len<tab->lengh)
{
merge_pass(tab,&tmp,len);
len = 2*len;
merge_pass(&tmp,tab,len);
len = 2*len;
}
}
9. 桶排序
桶排序(Bucket Sort)的原理很简单,它是将数组分到有限数量的桶子里。
假设待排序的数组a中共有N个整数,并且已知数组a中数据的范围[0, MAX)。在桶排序时,创建容量为MAX的桶数组r,并将桶数组元素都初始化为0;将容量为MAX的桶数组中的每一个单元都看作一个”桶”。
在排序时,逐个遍历数组a,将数组a的值,作为”桶数组r”的下标。当a中数据被读取时,就将桶的值加1。例如,读取到数组a[3]=5,则将r[5]的值+1。
桶排序不能应用于排序数很大的情况,因为这样会需要一个很大很大桶,显然是科学的。
桶排序是稳定的,最好的时间复杂度达到O(N)
/* * 桶排序 * tab -- 排序结构 * max --待排序结构中最大范围[0,max) */
void bucket_sort(table* tab,int max)
{
int i,j;
int* bucket;
if (tab == NULL || tab->lengh > max || max < 1)
return;
if ((bucket = (int*)malloc(sizeof(int)*max)) == NULL)
return;
memset(bucket,0,max*sizeof(int));
//1.计数
for (i = 1;i<tab->lengh;i++)
{
bucket[tab->r[i]]++;
}
//2.排序
for(i = 1,j = 1;i < max;i++)
{
while(bucket[i]-- != 0)
tab->r[j++] = i;
}
free(bucket);
}
基数排序
基数排序比较麻烦,自我认为找工作,面试笔试都不会考到,理解基本思路即可。
实现思路:
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。