最近为找工作,开始复习基本的算法和数据结构,由于平时除了看书,还有做项目,所以就安排晚上睡觉前复习一下基础理论。经过一周多的时间,终于把最基本的排序算法的理论和实现搞完了。记录下复习结果,方便以后参考。
在此声明:因为好长时间没有看排序算法了,有些算法理论记得不太清楚,参考了MoreWindows的一些关于排序算法博客。
如果需要了解更详细的排序算法的理论,可以关注MoreWindows的blog:http://blog.csdn.net/morewindows
/* 冒泡法排序
** 冒泡法原理:重复的查看要排序的数列,比较相邻的两个数,如果他们的次序不对就相互交换,
** 直到没有需要交换的相邻的两个数为止。
** 时间复杂度为O(n^2)
** 空间复杂度为O(1)
**/
void swap(int &x, int &y)
{
x = x^y;
y = x^y;
x = x^y;
}
void bubble_sort(int *array,int n)
{
int i,j;
for(i = 0; i<n-1;i++) //注意最好写成 i<n-1,而不是 i<n;虽然对结果没有影响
for(j = 1; j<n-i;j++)
if(array[j-1] > array[j]) //compare array[j-1] to array[j]
swap(array[j-1],array[j]);
/* {
int temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
}
*/
}
/* 插入法排序
** 原理:插入法排序就是将一个数插入到一个有序的数列中,
** 时间复杂度: O(n^2)
** 空间复杂度: O(1)
*/
void insert_sort(int array[],int len)
{
int i,j,temp;
for(i = 1; i < len ; i++)
{
temp = array[i]; //保存需要插入的数
for( j = i-1; j>=0; j--)
{
if(array[j] <= temp )
break; //当满足 temp <array[j+1] && temp > array[j],退出循环
array[j+1] = array[j];
}
//也可以这样写
#if 0
j=i-1;
while(j>=0 && array[j] > temp) //
{
array[j+1] = array[j];
}
#endif
array[j+1] = temp; //在array[j+1] 的位置上插入 array[i]
}
}
/*选择排序
**思想原理:从序列中选择一个最大(或者最小)的数放在序列的最后(或者开头)。
**选择排序是个不稳定的排序,
**时间复杂度:O(n^2)
**空间复杂度O(1)
*/
//#code1
void select_sort(int A[],int n)
{
int temp,index;
for(int i=n-1;i>0;i--) //note the boundary
{
index = i;
for(int j = i-1; j>=0;j--)
{
if(A[j] > A[index])
index = j;
}
temp = A[i];
A[i] = A[index];
A[index] = temp;
}
}
/*
//#code 2
void SelectSort(int A[], int n)
{
int temp , index;
for(int i=0;i<n-1;i++)
{
index = i;
for(int j= i+1;j<n;j++)
if(A[j]<A[index])
index = j;
temp = A[i];
A[i] = A[index];
A[index] = temp;
}
}
*/
/* 快速排序
** 基本思想:从序列中选定一个数 key,然后将序列分成两部分,左边部分的所有的数
** 都不大于key,而右边的数都不小于key,然后对这两部分的数分别进行快速排序,整个
** 排序可以通过递归的方法。
** 时间复杂度:平均O(nlog(n)),最坏O(n^2)(逆序);
** 空间复杂度:O(1)。
*/
void quick_sort(int A[], int n)
{
int i = 0, j = n-1;
int val = A[0];
if(n>1) //if array is empyt or just a elemnt,it doesn't need sort
{
while(i<j) //
{
for(;j>i;j--) //find the first element which is smaller than val from back.
if(A[j] < val)
{
A[i] = A[j];
break;
}
for(;i<j;i++)//find the first element which is greater than val from front.
{
if(A[i] > val)
{
A[j] = A[i];
break;
}
}
}
A[i] = val; //A[0] ~ A[i-1] <= val, A[i+1] ~ A[n] >= val
quick_sort(A,i); //sort the first i elements,A[0] ~ A[i-1]
quick_sort(A+i+1,n-i-1); //sort the last (n-i-1) elements,A[i+1] ~ A[n-1]
}
}
/* 归并排序
** 基本思想:把待排序的序列分成两个子序列,每个子序列都是有序的,然后合并两个有序的子序列。
** 该算法是采用分治策略的典型应用,首先将原序列分成两个子序列,然后对子序列再分成两个子序列,
** 直到子序列有序(一般只有一个元素),然后在将相邻的两个有序的序列合并(2路-合并),直到整个
** 都有序为止。
** 时间复杂度:O(nlog(n)) 空间复杂度:O(n)
*/
void Merge(int *A, int p, int q, int r)
{
int m = q-p+1, n = r-q;
int i=0,j=0,k=0;
int *r1 = (int *) malloc(sizeof(int) * (m));
int *r2 = (int *) malloc(sizeof(int) * (n));
//initialize r1 & r2
for(i=0; i<m; i++)
r1[i] = A[p+i];
for(i=0 ; i<n; i++)
r2[i] = A[q+i+1];
i=0;
j=0;
k=0;
while(i<m || j<n)
{
if(i<m && j<n)
{
if(r1[i] > r2[j])
A[p+k++] = r2[j++];
else
A[p+k++] = r1[i++];
}
else if(i>=m)
A[p+k++] = r2[j++];
else
A[p+k++] = r1[i++];
}
free(r1);
free(r2);
}
void MergeSort(int *A,int p , int r)
{
if(p<r)
{
int q = (p+r)/2;
MergeSort(A,p,q);
MergeSort(A,q+1,r);
Merge(A,p,q,r);
}
}
/* 计数排序
** 要求: 需要输入线性序列都在有限序列集 S 中。
** 基本思想:对于序列中任意一个元素A[i],找出序列中小于A[i]的元素个数k,那么就可以
** 确定A[i]在序列中位置为k+1。需要注意的是可能有重复的数。
** 时间复杂度:O(n+k)(k为序列中数值的范围),空间复杂度:O(k)
*/
void count_sort(int A[], const int max,const int n) //max为数组A中最大的数,n为数组A的元素个数
{
int i,j;
int *B = (int *)malloc(sizeof(int)*(max+1)); //0~max,总共有(max+1)个数
memset(B,0,(max+1)*sizeof(int));
for(i=0;i<=max;i++)
printf("%d ",B[i]);
printf("\n");
for(i=0;i<n;i++)
B[A[i]]++; //统计排序的个数
j=0;
for(i=0;i<=max;i++)
{
int temp = B[i];
while(temp--) //B[i]表示在A中有B[i]个元素 i
A[j++] = i;
}
free(B);
}
/* 希尔(shell)排序
** 基本思想:将整个待排序的序列分成若干子序列(相隔某一步长的元素),然后对每个子序列进行简单插入排序,再缩小
** 步长,继续对子序列进行插入排序,直到子序列基本有序,对整个序列进行一次排序,就可以完成排序
** 时间复杂度: O(n^(3/2))
** 空间复杂度: O(1)
*/
void shell_sort(int a[], int n)
{
int i,j,steps;
for(steps = n/2 ; steps > 0 ; steps /=2)
{
for(i=steps;i<n;i += steps) //从第二个元素开始,每次和之前的元素比较
{
if( a[i] < a[i-steps])
{
int temp = a[i];
j = i-steps;
while(j>=0 && a[j] > temp)
{
a[j+steps] = a[j];
j -= steps;
}
a[j+steps] = temp;
}
}
}
}
/* 堆排序
** 思想原理:首先要建立最小堆(或者最大堆),然后交换a[0] 和 a[n-1]
** 然后再维护a[0] 到 a[n-2]为最小堆(或者最大堆)
** 时间复杂度: O(nlog(n))
** 空间复杂度: O(1)
*/
/* 最小堆*/
void minHeap(int a[], int n ,int i)
{
int j = 2*i + 1;
while(j<n)
{
if( j+1 < n && a[j] > a[j+1])
j++;
if(a[i] <= a[j])
break;
int temp = a[i];
a[i] = a[j];
a[j] = temp;
i = j;
j = 2*i+1;
}
}
/*最大堆*/
void maxHeap(int a[],int n,int i)
{
int j= 2*i+1;
while(j<n)
{
if(j+1 < n && a[j+1] > a[j])
j++;
if(a[i]>=a[j])
break;
swap(a[i],a[j]); //这里采用在<utility.h>中的库函数
i = j;
j = 2*i+1;
}
}
/*建堆*/
void create_minheap(int a[] , int n)
{
for(int i = (n-1)/2; i>=0;i--)
maxHeap(a,n,i);
//minheap(a,n,i);
}
/*堆排序*/
void heap_sort(int a[],int n)
{
create_minheap(a,n);
for(int i = n-1;i>0;i--)
{
swap(a[0],a[i]);
maxHeap(a,i,0);
//minHeap(a,i,0);
}
}