版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38784098/article/details/78546065
//插入排序
void Insert_Sort(int *list,int count)
{
int temp;/*此处充当哨兵,不在list数组里面单独占一个单位*/
int i,j;
for(i=1;i<count;i++)
{
if(list[i]<list[i-1])
{
temp = list[i];
for(j=i-1;list[j]>temp&&j>=0;j--)
{
list[j+1] = list[j];
}
list[j+1] = temp;
}
}
}
效率:
时间复杂度:O(n^2).
其他的插入排序有二分插入排序,2-路插入排序。
//shell排序
void Shell_Sort(int *list,int count)
{
int i,j;
int temp;
int increment = count;
do
{
increment = increment/2;
for(i = increment;i<count;i++)
{
if(list[i]<list[i-increment])
{
temp = list[i];
for(j=i-increment;j>=0&&list[j]>temp;j-=increment)
{
list[j+increment] = list[j];
}
list[j+increment] = temp;
}
}
}while(increment>1);
}
希尔排序时效分析很难,关键码的比较次数与记录移动次数依赖于增量因子序列d的选取,特定情况下可以准确估算出关键码的比较次数和记录的移动次数。目前还没有人给出选取最好的增量因子序列的方法。增量因子序列可以有各种取法,有取奇数的,也有取质数的,但需要注意:增量因子中除1 外没有公因子,且最后一个增量因子必须为1。希尔排序方法是一个不稳定的排序方法。希尔排序时间复杂度的下界是n*log2n,因此中等大小规模表现良好。
//选择排序
void Select_Sort(int *list,int count)
{
int min,i,j;
for(i=0;i<count;i++)
{
min = i;
for(j=i+1;j<count;j++)
{
if(list[min]>list[j])
{
min = j;
}
}
if(min!=i)
{
swap(list[i],list[min]);
}
}
}
简单选择排序的改进——二元选择排序
简单选择排序,每趟循环只能确定一个元素排序后的定位。我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。
//调整为一个堆
void Heap_Adjust(int *list,int s,int m)
{
int temp = list[s];
for(int j=2*s+1;j<=m;j = 2*j+1)
{
if(list[j]<list[j+1]&&j<m)
{
j++;
}
if(temp>list[j])
break;
list[s] = list[j];
s = j;
}
list[s] = temp;
}
//堆排序
void Heap_Sort(int *list,int len)
{
//创建一个大顶堆
for(int s = len/2-1;s>=0;s--)
{
Heap_Adjust(list,s,len-1);
}
//排序
for(int i = len-1;i >= 1;i--)
{
swap(list[0],list[i]);
Heap_Adjust(list,0,i-1);
}
}
分析:
设树深度为k,。从根到叶的筛选,元素比较次数至多2(k-1)次,交换记录至多k 次。所以,在建好堆后,排序过程中的筛选次数不超过下式:
而建堆时的比较次数不超过4n 次,因此堆排序最坏情况下,时间复杂度也为:O(nlogn )。
由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。堆排序是就地排序,辅助空间为O(1),它是不稳定的排序方法。
//冒泡排序
void Bubble_Sort(int *list,int count)
{
int flag = true;
int i = 0,j = 0;
for(i=0;i<=count&&flag;i++)
{
flag = false;
for(j=count -1;j>=i;j--)
{
if(list[j]<list[j-1])
{
swap(list[j],list[j-1]);
flag = true;
}
}
}
}
//快速排序
int Partition(int *list,int low,int high)
{
int pivotKey;
pivotKey = list[low];
while(low<high)
{
while(low<high&&list[high]>=pivotKey)
{
high--;
}
swap(list[low],list[high]);
while(low<high&&list[low]<=pivotKey)
{
low++;
}
swap(list[low],list[high]);
}
return low;
}
void Qsort(int *list,int low,int high)
{
int pivot;
if(low<high)
{
pivot =Partition(list,low,high);
Qsort(list,low,pivot-1);
Qsort(list,pivot+1,high);
}
}
void Quick_Sort(int *list,int count)
{
Qsort(list,0,count-1);
}
分析:
快速排序是通常被认为在同数量级(O(nlog2n))的排序方法中平均性能最好的。但若初始序列按关键码有序或基本有序时,快排序反而蜕化为冒泡排序。为改进之,通常以“三者取中法”来选取基准记录,即将排序区间的两个端点与中点三个记录关键码居中的调整为支点记录。快速排序是一个不稳定的排序方法。
快速排序的改进
在本改进算法中,只对长度大于k的子序列递归调用快速排序,让原序列基本有序,然后再对整个基本有序序列用插入排序算法排序。实践证明,改进后的算法时间复杂度有所降低,且当k取值为 8 左右时,改进算法的性能最佳。
//归并排序
//将两个有序数组排序
void Merge(int *list,int start,int mid,int end)
{
const int len1 = mid -start +1;
const int len2 = end -mid;
const int len = end - start +1;
int i,j,k;
int * front = (int *)malloc(sizeof(int)*len1);
int * back = (int *)malloc(sizeof(int)*len2);
for(i=0;i<len1;i++)
front[i] = list[start+i];
for(j=0;j<len2;j++)
back[j] = list[mid+j+1];
for(i=0,j=0,k=start;i<len1&&j<len2&&k<end;k++)
{
if(front[i]<back[j])
{
list[k] = front[i];
i++;
}else
{
list[k] = back[j];
j++;
}
}
while(i<len1)
{
list[k++] = front[i++];
}
while(j<len2)
{
list[k++] = back[j++];
}
}
void MSort(int *list,int start,int end)
{
if(start<end)
{
int mid = (start+end)/2;
MSort(list,0,mid);
MSort(list,mid+1,end);
Merge(list,start,mid,end);
}
}
void Merge_Sort(int *list,int count)
{
MSort(list,0,count-1);
}
void Insert_Sort(int *list,int count)
{
int temp;/*此处充当哨兵,不在list数组里面单独占一个单位*/
int i,j;
for(i=1;i<count;i++)
{
if(list[i]<list[i-1])
{
temp = list[i];
for(j=i-1;list[j]>temp&&j>=0;j--)
{
list[j+1] = list[j];
}
list[j+1] = temp;
}
}
}
效率:
时间复杂度:O(n^2).
其他的插入排序有二分插入排序,2-路插入排序。
//shell排序
void Shell_Sort(int *list,int count)
{
int i,j;
int temp;
int increment = count;
do
{
increment = increment/2;
for(i = increment;i<count;i++)
{
if(list[i]<list[i-increment])
{
temp = list[i];
for(j=i-increment;j>=0&&list[j]>temp;j-=increment)
{
list[j+increment] = list[j];
}
list[j+increment] = temp;
}
}
}while(increment>1);
}
希尔排序时效分析很难,关键码的比较次数与记录移动次数依赖于增量因子序列d的选取,特定情况下可以准确估算出关键码的比较次数和记录的移动次数。目前还没有人给出选取最好的增量因子序列的方法。增量因子序列可以有各种取法,有取奇数的,也有取质数的,但需要注意:增量因子中除1 外没有公因子,且最后一个增量因子必须为1。希尔排序方法是一个不稳定的排序方法。希尔排序时间复杂度的下界是n*log2n,因此中等大小规模表现良好。
//选择排序
void Select_Sort(int *list,int count)
{
int min,i,j;
for(i=0;i<count;i++)
{
min = i;
for(j=i+1;j<count;j++)
{
if(list[min]>list[j])
{
min = j;
}
}
if(min!=i)
{
swap(list[i],list[min]);
}
}
}
简单选择排序的改进——二元选择排序
简单选择排序,每趟循环只能确定一个元素排序后的定位。我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。
//调整为一个堆
void Heap_Adjust(int *list,int s,int m)
{
int temp = list[s];
for(int j=2*s+1;j<=m;j = 2*j+1)
{
if(list[j]<list[j+1]&&j<m)
{
j++;
}
if(temp>list[j])
break;
list[s] = list[j];
s = j;
}
list[s] = temp;
}
//堆排序
void Heap_Sort(int *list,int len)
{
//创建一个大顶堆
for(int s = len/2-1;s>=0;s--)
{
Heap_Adjust(list,s,len-1);
}
//排序
for(int i = len-1;i >= 1;i--)
{
swap(list[0],list[i]);
Heap_Adjust(list,0,i-1);
}
}
分析:
设树深度为k,。从根到叶的筛选,元素比较次数至多2(k-1)次,交换记录至多k 次。所以,在建好堆后,排序过程中的筛选次数不超过下式:
而建堆时的比较次数不超过4n 次,因此堆排序最坏情况下,时间复杂度也为:O(nlogn )。
由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。堆排序是就地排序,辅助空间为O(1),它是不稳定的排序方法。
//冒泡排序
void Bubble_Sort(int *list,int count)
{
int flag = true;
int i = 0,j = 0;
for(i=0;i<=count&&flag;i++)
{
flag = false;
for(j=count -1;j>=i;j--)
{
if(list[j]<list[j-1])
{
swap(list[j],list[j-1]);
flag = true;
}
}
}
}
//快速排序
int Partition(int *list,int low,int high)
{
int pivotKey;
pivotKey = list[low];
while(low<high)
{
while(low<high&&list[high]>=pivotKey)
{
high--;
}
swap(list[low],list[high]);
while(low<high&&list[low]<=pivotKey)
{
low++;
}
swap(list[low],list[high]);
}
return low;
}
void Qsort(int *list,int low,int high)
{
int pivot;
if(low<high)
{
pivot =Partition(list,low,high);
Qsort(list,low,pivot-1);
Qsort(list,pivot+1,high);
}
}
void Quick_Sort(int *list,int count)
{
Qsort(list,0,count-1);
}
分析:
快速排序是通常被认为在同数量级(O(nlog2n))的排序方法中平均性能最好的。但若初始序列按关键码有序或基本有序时,快排序反而蜕化为冒泡排序。为改进之,通常以“三者取中法”来选取基准记录,即将排序区间的两个端点与中点三个记录关键码居中的调整为支点记录。快速排序是一个不稳定的排序方法。
快速排序的改进
在本改进算法中,只对长度大于k的子序列递归调用快速排序,让原序列基本有序,然后再对整个基本有序序列用插入排序算法排序。实践证明,改进后的算法时间复杂度有所降低,且当k取值为 8 左右时,改进算法的性能最佳。
//归并排序
//将两个有序数组排序
void Merge(int *list,int start,int mid,int end)
{
const int len1 = mid -start +1;
const int len2 = end -mid;
const int len = end - start +1;
int i,j,k;
int * front = (int *)malloc(sizeof(int)*len1);
int * back = (int *)malloc(sizeof(int)*len2);
for(i=0;i<len1;i++)
front[i] = list[start+i];
for(j=0;j<len2;j++)
back[j] = list[mid+j+1];
for(i=0,j=0,k=start;i<len1&&j<len2&&k<end;k++)
{
if(front[i]<back[j])
{
list[k] = front[i];
i++;
}else
{
list[k] = back[j];
j++;
}
}
while(i<len1)
{
list[k++] = front[i++];
}
while(j<len2)
{
list[k++] = back[j++];
}
}
void MSort(int *list,int start,int end)
{
if(start<end)
{
int mid = (start+end)/2;
MSort(list,0,mid);
MSort(list,mid+1,end);
Merge(list,start,mid,end);
}
}
void Merge_Sort(int *list,int count)
{
MSort(list,0,count-1);
}