(1)选择排序
算法思想:每次从待排序序列中选出最小值,和待排序序列第一个值交换。
不稳定(因为有跳跃式的数据交换)
时间复杂度:O(n^2) 性能 优于冒泡排序
空间复杂度:O(1)
void SelectSort(int *arr,int len)
{
int min;//值不好保存,要保存下标
int j;
int tmp;
for(int i= 0;i<len-1;i++)
{
min =i;
for(j =i+1;j<len;j++)
{
if(arr[min]>arr[j])
{
min = j;
}
}
if(i != min)
{
tmp = arr[i];
arr[i] = arr[min];
arr[min] = tmp;
}
}
}
优化:竞标排序(两两打擂台)很少见到
构成满二叉树时间复杂度:O(nlogn) 空间复杂度:O(n)
(2)堆排序()
简单选择排序的升级
大根堆排序思路:将待排序的序列构造成一个大根堆,此时,整个序列的最大值就是堆顶的根结点,将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个
元素中的次小值,如此反复执行,得到一个有序序列。
堆分为大根堆和小根堆两种
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大根堆,或者每个结点的值都小于或等于其左右孩子结点的值,称为小根堆
构建堆的时间复杂度:O(n)
重建堆的时间复杂度:O(nlogn)
总的时间复杂度:O(nlogn)
空间复杂度:O(1)
堆排序是一种不稳定的排序算法,不适合待排序序列个数较少的情况。
//一次堆调整
void Adjust(int *arr,int start,int end)//O(logn)
{
int tmp = arr[start];
int parent = start;
for(int i=2*start+1;i<=end;i=2*i+1)//
{ //父找子
if((i+1<=end) && (arr[i]<arr[i+1]))
{
++i;
}//i为左右孩子较大值的下标
if(tmp < arr[i])
{
arr[parent] = arr[i];
parent = i;
}
else
{
break;
}
}
arr[parent] = tmp;
}
void HeapSort(int *arr,int len)//O(nlog),,O(1),不稳定
{
int i;
for(i=(len-1-1)/2;i>=0;i--)//第一次建大根堆,O(nlogn)
{ //父找根
Adjust(arr,i,len-1);
}
int tmp;
for(i=0;i<len-1;i++)//O(nlogn)
{
tmp = arr[0];
arr[0] = arr[len-1-i];
arr[len-1-i] = tmp;//将根和最后的一个值交换
Adjust(arr,0,len-1-i-1);//进行堆调整,不包括最后一个
}
}
(3)归并排序
归并的定义:合并、并入,将两个或两个以上的有序表组合成一个新的有序表**归并排序:假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列长度是1,然后两两归并,得到【n/2】个长度为2或1的有序子序列,
再两两归并…….如此重复,直至得到一个长度为n 的有序序列为止,**这种排序方法称为 2路归并排序。
递归实现:时间复杂度:O(nlogn)
空间复杂度:O(n+logn)
非递归实现:空间复杂度:O(n)
**归并排序是一种比较占内存,但却效率高,且稳定的算法。
使用归并排序,尽量考虑用非递归。**
void Merge(int *arr,int len,int gap)//gap为归并段的长度
{
int low1 = 0;//第一个归并段的起始下标,下标可取
int high1 = low1+gap-1;//第一个归并段的结束下标,下标可取
int low2 =high1+1;// 第二个归并段的起始下标,下标可取
int high2 = low2+gap<len?low2+gap-1:len-1;//第二个归并段的结束下标,下标可取
int *brr = (int*)malloc(len*sizeof(int));
assert(brr!=NULL);
int i=0;//brr下标
while(low2<len)//保证有两个归并段
{
while(low1<=high1 && low2<=high2)
{
if(arr[low1]<=arr[low2])
{
brr[i++] = arr[low1++];
}
else
{
brr[i++] = arr[low2++];
}
}
while(low1<=high1)
{
brr[i++] = arr[low1++];
}
while(low2<=high2)
{
brr[i++] = arr[low2++];
}
low1 = high2+1;
high1 = low1+gap-1;
low2 = high1+1;
high2 =low2+gap<len-1?low2+gap-1:len-1;
}
//处理只有一个归并段的数据
while(low1<len)
{
brr[i++] = arr[low1++];
}
for(int i=0;i<len;i++)
{
arr[i] = brr[i];
}
free(brr);
}
void MergeSort(int *arr,int len)
{
for(int i=1;i<len;i*=2)
{
Merge(arr,len,i);
}
}
(4)基数排序(桶排序)针对于多关键字排序算法
算法思想:数字的话都是0—-9 准备10个桶。将数据按照一定规则先进先出(队列)
不需要关键字之间相互比较
空间复杂度:O(n) d*n
时间复杂度:O(n)
越有序越快
(5)链表排序(考试可能会考)
链表排序可以用冒泡排序实现(快速、插入、堆排序不合适)选择法排序也可以
void ListSort()
{
int tmp;
for(Node *p = plist->next;p->next!=NULL;p=p->next)
{
for(Node *q = plist->next;q->next != NULL;q=q->next)
{
if(q->data>q->next->data)
{
tmp = q->data;
q->data = q->next->data;
q->next->data = tmp;
}
}
}
}