堆排序
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。
因为这种排序方式为堆排,所以肯定要先创建一个堆
堆排序分为两个步骤:
- 1、堆排序需要一个大顶堆(每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆)或者小顶堆,最后堆排序结果一个正序一个逆序
void heapify(int tree[],int n,int i)
{
int max = i;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
if(c1 < n && tree[c1] > tree[max]) //筛选出最大的数的下标
{
max = c1;
}
if(c2 < n && tree[c2] > tree[max])
{
max = c2;
}
if(max != i)
{
swap(tree,max,i); //交换,让该结点的数大于孩子结点
}
}
2、创建一个堆
堆需要满足的条件是
对于堆中的任意一个三角形结构,顶部元素的值必须是三个数最大的,
每个三角形结构里有三个数(例如0,1,2 **** 1,3,4 **** 2,5,6****3,7,8都可以看做是一个三角形结构),在这三个数中去挑选出最大的数去作为顶部元素
如果想要满足堆的条件,就必须从堆的最底部元素开始遍历,才能够保证每个结点的值都大于孩子节点的值
- 怎么获得孩子节点和父节点
- 已知父结点,获得孩子结点的下标
- parent = i;
- c1 = 2 * i + 1;
- c2 = 2 * i + 2;
- 已知孩子结点,获得父节点的下标
- parent = (c1 - 1)/2;
- parent = (c2 - 1) / 2;
- 已知父结点,获得孩子结点的下标
找到所有的父节点就可以去遍历整个三角型结构,即构建成了一个堆
从上图中可以看到父节点为3,2,1,0.所以找到最后一个结点的下标,然后在找到其父节点,利用循环递减就可以遍历整个结构中的三角结构。
void build_heap(int tree[],int n)
{
int last_node = n - 1;
int parent = (last_node - 1) / 2;
for(int i = parent;i >= 0;i--)
{
heapify(tree,n,i);
}
}
到这里堆就构建完成了
堆排序思想:
构建好堆之后,把最大的元素即tree[0]和最后一个元素进行交换,这趟就将最大的元素 沉到了数组最低部,去掉这个最大的元素,对这个堆再进行heapify就构建成了一个新堆
这个新堆的元素个数为n - 1,在这个新堆继续把最大的元素沉到堆的底部,再去heapify
…
…
最终的数组就是一个有序数组
归并排序
归并排序利用分治思想,将一个数组打散,然后又合并成一个新的数组
-
第一次merge,会创建两个新的数组,假设arr1.left和arr2.right,这两个数组会将arr数组一分为二,并且会开始进行排序,返回排序内容给arr(此时的排序结果可能不对)
-
第二次merge仅考虑左半边,即数组arr1.left,会把arr1.left一分为二,创建数组arr2.left和arr2.right ,并把arr1.left的内容写入这两个数组,进入合并部分,会大致的进行排序,
-
第三次merge已经将一个大的数组分为了一个数字,一个数字一定有序,所以一定为得到正确的排序结果返回给arr2.left和arr2.right,逐层返回,最终存储到arr数组
-
这样逐级调用
-
第三次merge想要执行,就要去从形参arr中去获取地址,就要去找上一层merge,逐层递归,找到数组。
#include<stdio.h>
void merge(int *arr,int L,int M,int R)
{
int LEFT_SIZE = M - L;
int RIGHT_SIZE = R - M + 1;
int left[LEFT_SIZE];
int right[RIGHT_SIZE];
//分开
for(int i = 0;i < M;i++)
{
left[i-L] = arr[i];
}
for(int i = M;i <= R;i++)
{
right[i-M] = arr[i];
}
//合并
int i = 0,j = 0,k = L;
while( i < LEFT_SIZE && j < RIGHT_SIZE )
{
if(left[i] < right[j])
{
arr[k] = left[i];
k++;
i++;
}
else
{
arr[k] = right[j];
j++;
k++;
}
}
while(i < LEFT_SIZE)
{
arr[k] = left[i];
i++;
k++;
}
while(j < RIGHT_SIZE)
{
arr[k] = right[j];
j++;
k++;
}
}
void mergeSort(int * arr,int L,int R)
{
if(L == R)
return ;
else
{
int M = (L+R) / 2;
mergeSort(arr,L,M); //递归拆开数组并进行合并
mergeSort(arr,M+1,R);
merge(arr,L,M+1,R);
}
}
int main(void)
{
int a[100];
int n ;
printf("输入要排序的数据个数:");
scanf("%d",&n);
for(int i = 0; i < n;i++)
{
scanf("%d",&a[i]);
}
mergeSort(a,0,n-1);
for(int i = 0;i< n;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
}