浅谈排序

来源:互联网 发布:elle淘宝代购真的吗 编辑:程序博客网 时间:2024/05/22 11:33

1、堆排序

堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
(1)用大根堆排序的基本思想
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。
时间复杂度为O(log2n)
#include<iostream>using namespace std;const int N = 10;int arr[N];int parent(int i){   return i / 2;}//父节点 int left(int i) {   return 2 * i; }//孩子节点 int right(int i) {    return 2 * i + 1; }//右孩子节点 void heapadjust(int i,int n) {    int l,r,largest;l = left(i);r = right(i);if(l <= n && arr[l] > arr[i])largest = l;else largest = i;if(r <= n && arr[r] > arr[largest] )largest = r;if(largest != i){   swap(arr[i],arr[largest]);   heapadjust(largest, n);   /*         交换后子部分可能不满足堆性质,所以递归调整。         堆:对任意一棵树的任意一个非叶子节点,该节点值应该大于等于(或小于)左右子节点的数据结构.         若满足大于等于,则为大顶堆;反之为小顶堆         */  } } /* 初始调用buildheap将arr[1..n]变成最大堆 因为数组最大元素在arr[1],则可以通过将arr[1]与a[n]互换达到正确位置 现在新的根元素破坏了最大堆的性质,所以调用heapadjust调整, 使arr[1..n-1]成为最大堆,arr[1]又是arr[1..n-1]中的最大元素, 将arr[1]与arr[n-1]互换达到正确位置。 反复调用heapadjust(1, i - 1),使整个数组成从小到大排序。 */   void buildheap(int n)//自底向上是因为要使最大元素升至堆顶 {    for(int i = n / 2;i > 0;i--)heapadjust(i,n); }/* 交换只是破坏了以a[1]为根的二叉树最大堆性质,它的左右子二叉树还是具备最大堆性质。 这也是为何在build_maxheap时需要遍历n/2到1的结点才能构成最大堆,而这里只需要堆化arr[1]即可。 */  void heap_sort(int n) {    buildheap(n);for(int i = n;i > 1;i--){  swap(arr[1],arr[i]);  heapadjust(1,i-1);} } int main() { int i;   for(i = 1;i <= 10;i++)   cin>>arr[i];   heap_sort(10);    for(i = 1;i <= 10;i++)cout<<arr[i]<<" ";cout<<endl;return 0; }


2 、归并排序
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
其中时间复杂度为nlogn,空间复杂度为o(n)
#include<iostream>using namespace std;int a[20];//定义数组a[]int b[20];//定义辅助数组b[]void merge(int low,int mid,int high)//合并函数{     int i,j,k; i = low; j = mid + 1; k = low; while(i <= mid&&j <= high) {    if(a[i] > a[j])//找出小的数给数组b[] b[k++] = a[j++];else b[k++] = a[i++]; } while(i <= mid)//如果前一半没用完就继续给数组b[]  b[k++] = a[i++]; while(j <= high)//如果后一半没用完就继续给数组b[] b[k++] = a[j++]; for(i = low;i <= high;i++)//将合并完的数组b[]复制给数组a[] a[i] = b[i];}void merge_sort(int low,int high)//归并排序(其实就是递归的调用){  int mid;  if(low < high)  {     mid = (low+high) / 2; merge_sort(low,mid);//左边的一半再用merge_sort merge_sort(mid+1,high);//左边的一半再用merge_sort merge(low,mid,high);//将排好序的前一半数和后一半数合并了  }}int main(){int n,i;cin>>n;for(i = 0;i < n;i++)cin>>a[i];merge_sort(0,n-1);for(i = 0;i < n;i++)cout<<a[i]<<" ";cout<<endl;  return 0;}


0 0