总结一下面试常常遇到的基础排序算法(默认升序),方便接下来复习:
1.选择排序
思想:每一趟选出最小值
复杂度分析:最坏情况O(n^2),最好情况O(n^2),平均情况O(n^2),额外空间O(1)
稳定性:不稳定
例子:9 3 6 2 8 7
- 2 3 6 9 8 7 (第一趟)
- 2 3 6 9 8 7 (第二趟)
- 2 3 6 9 8 7 (第三趟)
- 2 3 6 7 8 9 (第四趟)
- 2 3 6 7 8 9 (第五趟)
- 2 3 6 7 8 9 (第六趟)
代码:
void selectSort(int *a,int len)
{
if(len <= 0) return;
for(int i=0;i<len-1;i++)
{
int min = a[i];
//这个循环选出第i趟最小值
for(int j=i+1;j<len;j++)
{
if(min>a[j])
{
min = a[j];
}
}
if(min != a[i])
{
swap(a,min,a[i]);
}
}
}
2.插入排序
思想:插入第i个元素时,与前面已经排好序的i-1个元素比较,如果它不是插入到最后一个位置,那么大于它的序列就要顺序向后移动一个位置。
复杂度分析:最坏情况O(n^2),最好情况O(n),平均情况O(n^2),额外空间O(1)
稳定性:稳定
例子:9 3 6 2 8 7
- 9 3 6 2 8 7(第一趟)
- 3 9 6 2 8 7(第二趟)
- 3 6 9 2 8 7(第三趟)
- 2 3 6 9 8 7(第四趟)
- 2 3 6 8 9 7(第五趟)
- 2 3 6 7 8 9(第六趟)
代码:
void insertSort(int *a,int len)
{
if(len <= 0) return;
for(int i=1;i<len;i++)
{
int j = i-1; //要插入的元素
int temp = a[i];
while(j>=0 && temp<a[j])
{
//后移
a[j+1] = a[j];
j--;
}
a[j+1] = temp; //多执行了一次j--,所以要+1
}
}
3.希尔排序(递减增量排序)
思想:相距增量(d)的元素为一组,内部采用插入排序方法使组内有序。然后增量减小一个单位,再组内排序,迭代直到增量为1。
复杂度分析:最坏情况O(n^1.3),最好情况O(n),平均情况O(n^2),额外空间O(1)
稳定性:不稳定
例子:9 3 6 2 8 7 (初始:元素个数为6,设置d= 6/2=3,那么9和2为一组,3和8为一组,6和7为一组)
- 2 3 6 9 8 7(第一趟d=3,9和2交换位置,其他两组已经有序)
- 2 3 6 7 8 9(第二趟d=2,2 6 8一组,3 9 7一组,9和7交换)
- 2 3 6 7 8 9(第三趟d=1,只剩一组,已经有序)
代码:
void shellSort(int *a,int len)
{
if(len <= 0) return;
for(int d=len/2;d>=1;d--)
{
for(int i=d;i<len;i++)
{
//每一组内部采取插入排序
if(a[i-d]>a[i])
{
int temp = a[i];
int k = i-d;
while(k>=0 && a[k]>= temp)
{
a[k+d] = a[k];
k = k-d;
}
a[k+d] = temp;
}
}
}
}
4.冒泡排序
思想:每一趟相邻元素两两比较,逆序则交换(想象成泡泡往上冒),每一次保证最大的到达顶部,排好序的最大元素不纳入下一趟排序。
复杂度分析:最坏情况O(n^2),最好情况O(n),平均情况O(n^2),额外空间O(1)
稳定性:稳定
例子:9 3 6 2 8 7
- 3 6 2 8 7 9(第一趟)
- 3 2 6 7 8 9 (第二趟)
- 2 3 6 7 8 9 (第三趟)
- 2 3 6 7 8 9 (第四趟)
- 2 3 6 7 8 9 (第五趟)
- 2 3 6 7 8 9 (第六趟)
代码:
void bubbleSort(int *a,int len)
{
if(len <= 0) return;
for(int i=len-1;i>0;i--)
{
for(int j=0;j<=i;j++)
{
if(a[j]>a[j+1])
{
swap(a,a[j],a[j+1]);
}
}
}
}
5.快速排序
思想:确定pivot之后(一般取第一位元素作为pivot),扫描一趟,比pivot小的放左边,比pivot大的放右边。再对左子序列和右子序列分别调用函数本身(递归),直到不能再分出左子序列和右子序列。
复杂度分析:最坏情况O(n^2),最好情况O(nlogn),平均情况O(nlogn),额外空间O(nlogn)
稳定性:不稳定
例子:4 8 2 6 5 3
- 2 3 4 8 6 5(第一趟)
- 2 3 4 6 5 8(第二趟)
- 2 3 4 5 6 8(第三趟)
代码:
void quickSort(int *a,int left,int right)
{
if(right <= left) return;
int pivot = a[left];
int i = left;
int j = right;
while(i < j)
{
while(j>i && a[j]>= pivot) //从右到左找比pivot小的
{
j--;
}
if(j>i)
{
a[i] = a[j];
i++;
}
while(j>i && a[i]<= pivot) //从左到右找比pivot小的
{
i++;
}
if(j>i)
{
a[j] = a[i];
j--;
}
}
a[i] = pivot; //完成一趟
quickSort(a,l,i-1); //左子序列
quickSort(a,i+1,r); //右子序列
}
6.归并排序
思想:
复杂度分析:最坏情况O(nlog),最好情况O(nlogn),平均情况O(nlogn),额外空间O(n)
稳定性:稳定
例子:4 8 2 6 5 3
- 4 8 2 | 6 5 3
- 4 | 8 2 | 6 | 5 3
代码:
void mergeSort(int *a,int first,int last, int *temp)
{
if(first < last)
{
int mid = (first + last)/2;
mergeSort(a,first,mid,temp); //对左子序列排序
mergeSort(a,mid+1,last,temp); //对右子序列排序
mergeArray(a,first,mid,last,temp); //合并
}
}
//两个有序子序列合并成一个新的序列
void mergeArray(int *a,int left,int mid,int right,int *temp)
{
int i = left, j = right;
int k = 0;
//循环挑出相对较小的放入临时数组temp中从而保证有序
while(i<=mid && j<=right)
{
if(a[i] < a[j])
{
temp[k++] = a[i++];
}else
{
temp[k++] = a[j++];
}
}
while(i <= mid) //如果左子序列还有剩,按序填入
{
a[k++] = a[i++];
}
while(j <= right) //如果右子序列还有剩,按序填入
{
a[k++] = a[j++];
}
//把temp中放回原数组
for(int m=0; m<k;m++)
{
a[first+m] = temp[m];
}
}
7.堆排序
思想:
复杂度分析:最坏情况O(nlogn),最好情况O(nlogn),平均情况O(nlogn),额外空间O(1)
稳定性:不稳定
性质:
1.节点的性质:i表示当前节点,则父节点为(i-1)/2,左孩子节点为(2*i+1),右孩子节点为(2 *i+2);
2.最大堆的父节点要大于等于子节点,(最小堆相反);
3.在新建堆的过程中,采用AdjustDown堆化数组,从n/2节点开始,因为大于n/2的是叶子节点。
代码:
//以最大堆为例
//堆调整
void AdjustDown(int a[],int k,int len)//将元素a[k]向下调整
{
a[0] = a[k]; //a[0]暂存,相当于temp
for(int i=2*k; i<=len; i*=2)
{
if(i<len && a[i]<a[i+1])
{
i++; //取值较大的i的下标
}
if(a[0]>=a[i])
{
break; //a[0]>子节点中最大的值,结束筛选
}else
{
a[k] = a[i]; //否则交换
k = i; //跟踪k的下标
}
}
a[k] = a[0]; //调整结束后,把a[k]的值补上
}
//新建堆
void BuildMaxHeap(int a[],int len)
{
for(int i=len/2;i>0;i--) //从i=len/2 - 1,反复调整堆
{
AdjustDown(a,i,len); //从上往下调整直到子树满足最大堆
}
}
//堆排序--调用前两个函数
void HeapSort(int a[],int len)
{
BuildMaxHeap(a,len); //初始建堆
for(int i=len;i>1;i--)
{
swap(a[i],a[1]); //可得到堆顶元素
AdjustDown(a,1,i-1); //整理剩余的i-1个元素
}
}
写到后面有点晕掉了,…(◎ロ◎)… ,休息一下…