您的位置:首页 > 理论基础 > 数据结构算法

数据结构之排序大集合(下)(选择、堆、基数、归并,链表排序)

2018-01-26 14:24 525 查看
(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
4000
];
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;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: