1.二路归并
/*********************************************************************************************** 1.设定两个指针,最初位置分别为两个已经排序序列的起始位置 2.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 3.重复步骤3直到某一指针达到序列尾 4.将另一序列剩下的所有元素直接复制到合并序列尾 归并排序: 归并排序具体工作原理如下(假设序列共有n个元素): 1.将序列每相邻两个数字进行归并操作,形成floor(n / 2)个序列,排序后每个序列包含两个元素 2.将上述序列再次归并,形成floor(n / 4)个序列,每个序列包含四个元素 3.重复步骤2,直到所有元素排序完毕 归并排序是稳定的,它的最差,平均,最好时间都是O(nlogn)。但是它需要额外的存储空间. 归并排序法(Merge Sort,以下简称MS)是分治法思想运用的一个典范。 其主要算法操作可以分为以下步骤: Step 1:将n个元素分成两个含n/2元素的子序列 Step 2:用MS将两个子序列递归排序(最后可以将整个原序列分解成n个子序列) Step 3:合并两个已排序好的序列 ************************************************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<climits> #include<cstdlib> #include<time.h> #include<cstdlib> #include<cstdio> using namespace std; void Random(int a[],int n) { int i=0; srand( (unsigned)time( NULL ) ); while(i<n) { a[i++]=rand(); } } void merge(int *a, int low, int mid, int high) //归并操作 { int k, begin1, begin2, end1, end2; begin1 = low; end1 = mid; begin2 = mid + 1; end2 = high; int *temp = (int *) malloc((high - low + 1) * sizeof(int)); for(k = 0; begin1 <= end1 && begin2 <= end2; k++) //自小到大排序 { if(a[begin1] <= a[begin2]) temp[k] = a[begin1++]; else temp[k] = a[begin2++]; } if(begin1 <= end1) //左剩 memcpy(temp + k, a + begin1, (end1 - begin1 + 1) * sizeof(int)); else //右剩 memcpy(temp + k, a + begin2, (end2 - begin2 + 1) * sizeof(int)); memcpy(a + low, temp, (high - low + 1) * sizeof(int)); //排序后复制到原数组 free(temp); //释放空间 } void merge_sort(int *a, unsigned int begin, unsigned int end) { int mid; if(begin < end) { mid=begin+(end-begin)>>1; //mid = (end + begin) / 2; 防止数据加法溢出 merge_sort(a, begin, mid); //分治 merge_sort(a, mid + 1, end); //分治 merge(a, begin, mid, end); //合并两个已排序的数列 } } int main() { int a[20]; Random(a,20); for(int i=0;i<20;i++) { cout<<" "<<a[i]<<" "; } merge_sort(a, 0, 20-1); for(int i=0;i<20;i++) { cout<<" "<<a[i]<<endl; } return 0; }
2.冒泡排序 插入排序 选择排序
#include <cstdio> #include<time.h> #include<cstdlib> #include<cstdio> using namespace std; /********创建数组,并输入元素************/ void Random(int a[],int n) { int i=0; srand( (unsigned)time( NULL ) ); while(i<n) { a[i++]=rand()/655; } } /**********遍历输出数组元素*************/ void Traverse(int arr[], int count) { int i; printf("array output:\n"); for(i=0; i<count; i++ ) printf("%d\t", arr[i]); printf("\n"); } /******************************************************* 冒泡排序 算法:将相邻的两个数比较,将小的调到前头; 有n个数,则要进行n-1趟比较,第一次比较中要进行 n-1次两两比较,在第j趟比较要进行n-j次两两比较 ********************************************************/ void BublleSort(int arr[], int count) { int i,j,temp; for(j=0; j<count-1; j++ ) /* 气泡法要排序n-1次*/ for(i=0; i<count-j-1; i++ )/* 值比较大的元素沉下去后,只把剩下的元素中的最大值再沉下去就可以啦 */ { if(arr[i]>arr[i+1])/* 把值比较大的元素沉到底 */ { temp=arr[i+1]; arr[i+1]=arr[i]; arr[i]=temp; } } } /******************************************************* 插入排序 算法: 在得到要排序的数组以后,将数组分为两部分, 数组的第一个元素为一部分,剩下的元素为一部分, 然后从数组的第二个元素开始,和该元素以前的所有元素比较, 如果之前的元素没有比该元素大的,那么该元素的位置不动, 如果有的元素的值比该元素大,那么记录下他所在的位置, 例如为i,该元素的位置例如为k,则将从i到k位置上的 所有元素统统向后移动,然后将k移到i元素的位置上。 这样就找到了k所在的位置。每一个元素都这样进行, 最终就会得到排好顺序的数组。 ********************************************************/ void InsertSort(int arr[],int count) { int i,j,temp; for(i=1; i<count; i++ )//数组分两个部分,从第二个数组元素开始 { temp = arr[i];//操作当前元素,先保存在其它变量中 for(j=i-1; j>=0&&arr[j]>temp;j--)//从当前元素的上一个元素开始查找合适的位置,一直查找到首元素 { arr[j+1] = arr[j]; } if(j!=(i-1)) /*第i个数字比前面的都大,不需要重新插入*/ { arr[j+1]=temp; } } } /******************************************************* 选择排序 算法:首先以一个元素为基准,从一个方向开始扫描, 比如从左至右扫描,以A[0]为基准。接下来从A[0]...A[9] 中找出最小的元素,将其与A[0]交换。然后将基准位置右 移一位,重复上面的动作,比如,以A[1]为基准,找出 A[1]~A[9]中最小的,将其与A[1]交换。一直进行到基准位 置移到数组最后一个元素时排序结束(此时基准左边所有元素 均递增有序,而基准为最后一个元素,故完成排序)。 ********************************************************/ void SelectSort(int arr[], int count) { int i,j,min,temp; for(i=0; i<count-1; i++) { min = i;//以此元素为基准 for(j=i+1; j<count;j++ )//从j往前的数据都是排好的,所以从j开始往下找剩下的元素中最小的 { if(arr[min]>arr[j])//把剩下元素中最小的那个放到arr[j]中 { min = j; } if(min!=i) { temp=arr[min]; arr[min]=arr[i]; arr[i]=temp; } } } } const int count=20; int main() { int array[count]={0}; Random(array,count); Traverse(array, count);//输出最初数组 //BublleSort(array, count);//冒泡排序 //Traverse(array, count);//输出排序后的数组 //InsertSort(array, count);//插入排序 //Traverse(array, count);//输出排序后的数组 SelectSort(array, count);//插入排序 Traverse(array, count);//输出排序后的数组 return 0; }
选择排序
从字面上理解,就是通过不断地选择数组元素,从而达到排序的目的。我插入排序类似,假设第i(i<n)个数组元素data[0]是最大的(从大到小排序),然后依次扫描i + 1 到 n - 1的元素,找到比第i个元素大的元素。最后将它们交换。
算法的时间复杂度为O(n^2)。
算法的实现如下
希尔排序(shellsort)算法实现
希尔排序(shellsort)又叫增量递减(diminishing increment)排序,是由D.L. Shell发明的,这个算法是通过一个逐渐减小的增量使一个数组逐渐趋近于有序从而达到排序的目的。
假设有一个数组int data[16] = {...}。 首先将这个增量设为16 / 2 = 8, 这样就将这个数组分成了8个子数组,它们的索引是0, 8 1, 9 2, 10等等 。对这些子数组进行排序。然后再使增量为8 / 2 = 4,这样就将原数组分成了4个子数组,它们的索引分别是0, 4, 8, 12 1, 5, 9, 13等等。再对这四组数进行排序,直到增量为1。
以上所描述的增量递减只是一种方法,这种方法并不是最有效率的。如f(n) = 3 * f(n - 1) + 1 f(1) = 1 (..., 121, 40, 13, 4, 1)就比上面的取增量的方法好。这种方法的时间复杂度是O(n ^1.5)。
算法如下
归并排序(merge sort)算法实现
归并排序(merge sort)体现了分治的思想,即将一个待排序数组分为两部分,对这两个部分进行归并排序,排序后,再对两个已经排序好的数组进行合并。这种思想可以用递归方式很容易实现。归并排序的时间复杂度为O(nlogn),空间复杂度为O(n)。
实现代码如下:
#include <stdio.h>
#include "common.h"
void merge(int data[], int p, int q, int r)
{
int i, j, k, n1, n2;
n1 = q - p + 1;
n2 = r - q;
int L[n1];
int R[n2];
for(i = 0, k = p; i < n1; i++, k++)
L[i] = data[k];
for(i = 0, k = q + 1; i < n2; i++, k++)
R[i] = data[k];
for(k = p, i = 0, j = 0; i < n1 && j < n2; k++)
{
if(L[i] > R[j])
{
data[k] = L[i];
i++;
}
else
{
data[k] = R[j];
j++;
}
}
if(i < n1)
{
for(j = i; j < n1; j++, k++)
data[k] = L[j];
}
if(j < n2)
{
for(i = j; i < n2; i++, k++)
data[k] = R[i];
}
}
void merge_sort(int data[], int p, int r)
{
if(p < r)
{
int q = (p + r) / 2;
merge_sort(data, p, q);
merge_sort(data, q + 1, r);
merge(data, p, q, r);
}
}
void test_merge_sort()
{
int data[] = {44, 12, 145, -123, -1, 0, 121};
printf("-------------------------------merge sort----------------------------/n");
out_int_array(data, 7);
merge_sort(data, 0, 6);
out_int_array(data, 7);
}
int main()
{
test_merge_sort();
return 0;
}
快速排序(quicksort)算法实现
快速排序(quicksort)是分治法的典型例子,它的主要思想是将一个待排序的数组以数组的某一个元素X为轴,使这个轴的左侧元素都比X大,而右侧元 素都比X小(从大到小排序)。然后以这个X在变换后数组的位置i分为左右两个子数组,再分别进行快速排序,直到子数组中只有一个元素为止。
快速排序算法如下