标签:
直接选择排序:
原理:每次从未排序的序列中找到最小值,记录并最后存放到已排序序列的结尾
性能:时间复杂度为O(N^2)空间复杂度为O(1),排序是不稳定的(把最小值交换到已排序的结尾导致的),每次都能确定一个元素所在的最终位置,比较次数与初始序列无关。
void select_sort(int value[], int length) { int i,j; for(i=0;i<length-1;i++) { int min=i; for(j=i+1;j<length;j++) { if(value[min]>value[j]) { min=j; } } if(min!=i) { swap(value[i],value[min]); } } }
快速排序
快速排序是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
对于基准数的选择,本程序使用中间值作为基准数,下面是程序实现:
#include<stdio.h> #include<time.h> #include<stdlib.h> void swap(int *a ,int *b) { int t = *a; *a = *b; *b = t; } int partition(int array[],int l,int r) { int pivot = array[r]; int curpos = l; int j ; for( j = l;j<r;j++) { if(array[j] < pivot) { swap(&array[j],&array[curpos]); curpos++; } } swap(&array[r],&array[curpos]); return curpos; } void quicksort(int array[],int l,int r) { int interval; if(l < r) { interval = partition(array,l,r); quicksort(array,l,interval-1); quicksort(array,interval+1,r); } } int test_quicksort() { int i; int number = 12; int *array = malloc(number*sizeof(int)); if(array == NULL) { printf("malloc failed\n"); return -1; } printf("----------------------------------------before quick sort--------------\n"); srand(time(NULL)); for(i = 0;i<number;i++) { array[i] = rand()%1000; printf("\tarray[%d] = %d\n",i,array[i]); } printf("----------------------------------------after quick sort-----------------\n"); quicksort(array,0,number-1); for(i = 0;i<number;i++) { printf("\tarray[%d] = %d\n",i,array[i]); } return 0; } int main() { test_quicksort(); }
归并排序:
分而治之思想:
1.Divide: 将n个元素平均划分为各含n/2个元素的子序列;
2.Conquer: 递归的解决两个规模为n/2的子问题;
3.Combine: 合并两个已排序的子序列。
性能:时间复杂度总是为O(NlogN),空间复杂度为O(N),算法与初始序列无关,排序也是稳定的
优化:
1. 在规模较小时,合并排序可以采用直接插入
2.在写法上,可以在生成辅助数组时,两头小,中间大,这是不需要在后边加两个while循环进行判断,只需一次比完。
比较v[indexA]=7和v[indexB]=12,将较小的v[indexA]取出来放到临时向量tempArray中,然后indexA加1
代码:
#include<stdlib.h> typedef int RecType;//要排序元素类型 void Merge(RecType *R,int low,int m,int high) { //将两个有序的子文件R[low..m)和R[m+1..high]归并成一个有序的子文件R[low..high] int i=low,j=m+1,p=0; //置初始值 RecType *R1; //R1是局部向量 R1=(RecType *)malloc((high-low+1)*sizeof(RecType)); if(!R1) { return; //申请空间失败 } while(i<=m&&j<=high) //两子文件非空时取其小者输出到R1[p]上 { R1[p++]=(R[i]<=R[j])?R[i++]:R[j++]; } while(i<=m) //若第1个子文件非空,则复制剩余记录到R1中 { R1[p++]=R[i++]; } while(j<=high) //若第2个子文件非空,则复制剩余记录到R1中 { R1[p++]=R[j++]; } for(p=0,i=low;i<=high;p++,i++) { R[i]=R1[p]; //归并完成后将结果复制回R[low..high] } } void MergeSort(RecType R[],int low,int high) { //用分治法对R[low..high]进行二路归并排序 int mid; if(low<high) { //区间长度大于1 mid=(low+high)/2; //分解 MergeSort(R,low,mid); //递归地对R[low..mid]排序 MergeSort(R,mid+1,high); //递归地对R[mid+1..high]排序 Merge(R,low,mid,high); //组合,将两个有序区归并为一个有序区 } } void main() { int a[7]={49,38,65,97,76,13,27}; //这里对8个元素进行排序 int low=0,high=6; //初始化low和high的值 printf("Before merge sort: "); for(int i=low;i<=high;i++) { printf("%d ",a[i]); //输出测试 } printf("/n"); MergeSort(a,low,high); printf("After merge sort: "); for( i=low;i<=high;i++) { printf("%d ",a[i]); //输出测试 } printf("/n"); }
优化代码:
void Merge(int arr[],int temp_arr[],int left,int mid,int right) { //简单归并,先复制到temp_arr,再进行归并 int i; for(i=left,i<=right;i++) { temp_arr[i]=arr[i]; } int pa = left, int pb=mid+1; int index = left; while(pa<=mid && pb<=right) { //两子文件非空时取其小者输出到arr上 if(temp_arr[pa] <= temp_arr[pb]) { arr[index++] = temp_arr[pa++]; } else { arr[index++] = temp_arr[pb++]; } } //复制没有比较完子表中的元素 while(pa<=mid) //若第1个子文件非空,则复制剩余记录到R1中 { arr[index++]=temp_arr[pa++]; } while(pb<=right) //若第2个子文件非空,则复制剩余记录到R1中 { arr[index++]=temp_arr[pb++]; } } void Merge_improve(int arr[],int temp_arr[],int left,int mid,int right) { //优化归并;复制时,两头小,中间大,一次比较完 int i; for(i=left;i<=mid;i++) { temp_arr[i]=arr[i]; } for(i=mid+1;i<=right;i++) { temp_arr[i]=arr[right+mid+1-i]; } int pa = left; int pb = right; int p = left; while(p<=right) { if(temp_arr[pa]<=temp_arr[pb]) { arr[p++]=temp_arr[pa++]; } else { arr[p++]=temp_arr[pb--]; } } } void MergeSort(int arr[],int temp_arr[],int left,int right) { //用分治法对R[left..right]进行二路归并排序 if(left<right) { //区间长度大于1 int mid=(left+right)/2; //分解 MergeSort(arr,temp_arr,0,mid); //递归地对R[low..mid]排序 MergeSort(arr,temp_arr,mid+1,right); //递归地对R[mid+1..high]排序 Merge(arr,temp_arr,left,mid,right); //组合,将两个有序区归并为一个有序区 } } void MergeSort(int arr[],int len) { int *temp_arr = (int *)malloc(sizeof(int)*len); Mergesort(arr,temp_arr,0,len-1); }
void shiftDown(int arr[], int start, int end)
{
//从start出发到end,调整为最大堆
int dad = start;
int son = dad * 2 + 1;
while (son <= end){
//先选取子节点中较大的
if (son + 1 <= end && arr[son] < arr[son + 1])
{
son++;
}
//若子节点比父节点大,则交换,继续往子节点寻找;否则退出
if (arr[dad] < arr[son])
{
swap(arr[dad], arr[son]);
dad = son;
son = dad * 2 + 1;
}
else
{ break; }
}
}
void heap_sort(int arr[], int len)
{ //先调整为最大堆,再依次与第一个交换,进行调整,最后构成最小堆
for (int i = (len - 2) / 2; i >= 0; i--)
{
//len为总长度,最后一个为len-1,所以父节点为 (len-1-1)/2
shiftDown(arr,i,len-1);
}
for (int i = len - 1; i >= 0; i--)
{
swap(arr[i], arr[0]);
shiftDown(arr, 0,i-1);
}
}
#include <stdio.h> #define N 1000 #define INF 999999999 int h[N]; //调整堆(迭代法) //n:规模 i:二叉子堆的堆顶 void heapAdjust(int n, int par) { int tmp, pos, lc, rc; while (par <= n/2) { tmp = h[par]; //记录父母结点键值 lc = par<<1; rc = lc+1; pos = par; //父母结点至多更新2次 if (h[par] < h[lc]) { h[par] = h[lc]; pos = lc; } if (rc <= n && h[par] < h[rc]) { h[par] = h[rc]; pos = rc; } if (pos == par) //无更新即无需调整 break; else h[pos] = tmp; par = pos; //假设这个位置的结点是“父母结点” } } //创建堆 //规模为n的堆,对其父母结点,自底向上自右向左地调整堆 void createHeap(int n) { int i; for (i = n/2; i != 0; i--) { heapAdjust(n, i); } } void heapSort(int n) { int ntimes = n; while (ntimes--) { printf("%d\n", h[1]); h[1] = h[n]; h[n--] = 0; //堆清零 heapAdjust(n, 1); } } int main(void) { int n, i; scanf("%d", &n); h[0] = INF; for (i = 1; i != n+1; i++) { scanf("%d", &h[i]); } createHeap(n); heapSort(n); return 0; }
标签:
原文地址:http://blog.csdn.net/qq_24338883/article/details/51422149