数据分析之路|面试题整理之常见算法篇

几种常见排序算法及实现

1.冒泡排序(Bubble Sort)

相邻两个元素作比较,冒泡排序是稳定的。算法时间复杂度是O(n^2)。
基本思想:
1)第一轮比较,找出最大的元素;第二轮找出次大的元素……

2)若有N个元素进行排序,一共比较N-1轮,第M轮要进行N-M次比较;

3)代码实现:

  static void BubbleSort(int[] arr){
for (int times=1,times<=arr.length-1,times++)  //比较arr.length-1轮
{
  for (int i=1,i<=arr.length-times,i++)  //每一轮比较arr.length-times次
  {
if (arr[i-1]>arr[i]){
temp=arr[i-1]
arr[i-1]=arr[i] 
arr[i]=temp
}
  }
}
  }

2.选择排序(Select Sort)

用某一位置的元素依次与其它位置元素相比较。直接选择排序是不稳定的,算法平均时间复杂度是O(n^2)。
基本思想:
(1)第一轮比较完毕,出现最小值,第二轮比较完毕,出现次小值……

(2)与冒泡算法一样,若有N个元素进行排序,一共比较N-1轮,第M轮要进行N-M次比较,但是每一轮只交换一次数值

(3)代码实现:

static void SelectSort(int[] arr){
for (int times=0,times<=arr.length-1,times++)  //以索引为0的元素作为第一个元素,依次与其它元素进行比较。
{
  int minindex=times
  for (int i=times+1,i<=arr.length,i++)  //i代表索引为i的被比较元素,可以取到arr.length。
  {
if (arr[i]<arr[minindex]){
minindex=i }
  }
  temp=arr[times]
  arr[times]=arr[minindex] 
  arr[minindex]=temp
}
  }

3.快速排序

快速排序是对冒泡排序的一种改进。
快速排序是不稳定的。最理想情况算法时间复杂度O(nlog2n),最坏O(n ^2)。
基本思想:
(1)首先任意选择一个元素作为初始元素key(一般取第一个元素)

(2)从两端开始分别找:从右往左,寻找比key值小的元素交换位置;再从左往右,寻找比key值大的元素交换位置;

(3)如此依次循环步骤1.2

(4)代码实现:

void quicksort(int left,int right)  
{  
if(left>right) return ;  
else  
{  
int i=left;  
int j=right;  
T t;  
T temp=data[left];  
while(i!=j)  
{  
while(i<j&&data[j]>=temp) j--;  //记住必须先动j   
while(i<j&&data[i]<=temp) i++;  
if(i!=j) swap(i,j);  //原地交换   
}  
swap(left,i);  
quicksort(left,i-1);  
quicksort(i+1,right);   
}  
}  

4.堆排序

堆排序是一种树形选择排序。
堆排序的时间复杂度为O(n*log(n)), 非稳定排序,原地排序(空间复杂度O(1))。

基本思想:分为最大化堆和最小化堆。

第1趟将索引0至n-1处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的最后一个节点交换,就使的这组数据中最大(最小)值排在了最后。

第2趟将索引0至n-2处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的倒数第二个节点交换,就使的这组数据中最大(最小)值排在了倒数第2位。

第k趟将索引0至n-k处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的倒数第k个节点交换,就使的这组数据中最大(最小)值排在了倒数第k位。

代码实现

#include<memory.h>
#include<stdio.h>
#include<stdlib.h>
void swap(void* x, void* y, size_t sz) {
void* t = malloc(sz);
memcpy(t, x, sz);
memcpy(x, y, sz);
memcpy(y, t, sz);
free(t);
}
void makeHeap(void* x, int i, int n, size_t sz, int(*cmp)(const void*, const void*)) {
char* y = (char*)x;
int l = 2 * i + 1;
int r = 2 * i + 2;
int m;
if (l<n && (*cmp)(y + l*sz, y + i*sz)>0) m = l;
else m = i;
if (r<n && (*cmp)(y + r*sz, y + m*sz)>0) m = r;
if (m != i){
swap(y + i*sz, y + m*sz, sz);
makeHeap(x, m, n, sz, cmp);
}
}
void buildHeap(void* x, int n, size_t sz, int(*cmp)(const void*, const void*)) {
for (int i = n / 2 - 1; i >= 0; i--) makeHeap(x, i, n, sz, cmp);
}
void heapSort(void* x, int n, size_t sz, int(*cmp)(const void*, const void*)) {
buildHeap(x, n, sz, cmp);
char* y = (char*)x;
for (int i = n - 1; i >= 1; i--){
swap(y, y + i*sz, sz);
makeHeap(x, 0, --n, sz, cmp);
}
}

void p(int* x,int n){
for (int k = 0; k < n; k++){
printf("%d ", x[k]);
}
printf("\n");
}

int less(const void* a, const void* b){
return *((int*)a) < *((int*)b);
}
int greater(const void* a, const void* b){
return *((int*)a) *((int*)b);
}
int main(){
int x[] = { 2, 3, 4, 6, 8, 2, 9, 0 };
// 降序全排列
heapSort(x, 8, sizeof(int), less);
p(x, 8);
// 升序全排列
heapSort(x, 8, sizeof(int), greater);
p(x, 8);
// 最大的4个元素,在数组末尾
heapSort(x, 4, sizeof(int), less);
p(x, 8);
}

5.归并排序

是建立在归并操作上的一种有效的排序算法。

该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

算法时间复杂度可以达到O(n)

代码实现

void mergearray(int a[], int first, int mid, int last, int temp[])  
{  
int i = first, j = mid + 1;  
int m = mid,   n = last;  
int k = 0;  

while (i <= m && j <= n)  
{  
if (a[i] <= a[j])  
temp[k++] = a[i++];  
else  
temp[k++] = a[j++];  
}  

while (i <= m)  
temp[k++] = a[i++];  

while (j <= n)  
temp[k++] = a[j++];  

for (i = 0; i < k; i++)  
a[first + i] = temp[i];  
}  
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); //再将二个有序数列合并  
}  
}  

bool MergeSort(int a[], int n)  
{  
int *p = new int[n];  
if (p == NULL)  
return false;  
mergesort(a, 0, n - 1, p);  
delete[] p;  
return true;  
}  

参考文章

  1. 2017校招数据分析岗笔试/面试知识点

  2. 快速排序全面讲解(含复杂度证明)——即将引出八大排序算法

  3. 白话经典算法系列之五 归并排序的实现(讲的真好)

  4. 堆排序原理及其实现(C++)


------------------本文结束感谢您的阅读------------------
坚持原创技术分享,您的支持将鼓励我继续创作!