算法:面试和工作中常用的算法-排序

前几天一直在纠结算法的问题,可自己研究了下也没啥成效,不知道哪些是重点,眉毛胡子一把抓肯定效果不好的。所以今天把这些比较容易用到的算法总结一下,相当于是让大家有个更好的方式理解,也帮助我自己更好的深入学习。排序应该算是我们工作中用的最普遍的算法之一了。其中冒泡排序,选择排序和插入排序更是基础中的基础,是大家一定要熟练掌握的(能够快速手写)。
首先我们明确几个概念:
时间复杂度:书面意思都说的很官方,我的理解就是一个排序算法经过多少次循环完成排序的,然后用公式算出一个通用的结果,将常数去掉。
空间复杂度:就是你在排序的过程中需要额外消耗的内存。
内排序:排序可以在自己的内存中完成
外排序:排序可能需要借助外部存储空间。一般外排序的空间复杂度较高
稳定:当两个相等的元素经过排序之后,先后顺序保持一致的话那么就是稳定,先后顺序变了那就是不稳定。
下面可以看下所有的算法:

我们今天讲的是我们面试中或者工作中经常会碰到的排序算法。如果需要了解其他算法的实现方式可以参考:            https://blog.csdn.net/weixin_41190227/article/details/86600821
这篇文章写的很详细,可以帮你解决其他排序相关的问题。
## 冒泡排序
原理:从头开始遍历,遍历到每个元素时每次都重复走一遍要排序的数组,如果元素顺序错误,就交换位置。这样小的元素就会浮到数组的顶端,大的元素会沉到数组的底部。因此称为冒泡排序。
代码示例:
void bubbleSort(int *data, int length) {
    int i, j;
    int temp = 0;
    for (i = 0; i < length; i++) {
        for (j = 0; j < length - i - 1; j++) {
		    if (data[j + 1] < data[j]) {
				temp = data[j + 1];
				data[j + 1] = data[j];
				data[j] = temp;
			}
		}
    }
}
时间复杂度:O(n2)最好:O(n2)最壞:O(n2)
空间复杂度:O(1)
## 插入排序
原理:同样也是需要经过两次循环完成。外层循环用于便利经过每个元素,内层循环用于比较,每个元素都与前面排好序的元素比较,如果顺序正常就将数组元素前移,当发现第一个小于(或大于)排好序元素的值时就找到元素的位置,这是插入。
代码示例:
void insertSort(int *data, int length) {
    int i, j;
    int temp = 0;
    for (i = 1, j = 0; i < length; i++) {
    	temp = data[i];
		for (j = i - 1; j >= 0 && temp < data[j]; j--) {
			data[j + 1] = data[j];
		}
		data[j + 1] = temp;
	}
}
时间复杂度:O(n2)最好:O(n)最坏:O(n2)
##选择排序
原理:选择排序应该是表现最稳定的排序算法之一了,因为他的复杂度一直是O(n2)。所以比较适合小规模数组的排序,并且不会额外消耗空间。算法是每次都在无序的数组中选择最小的放在最前面,这样每次都从剩下的无序数组中挑出最小的,这样就完成排序。
代码示例:
void selectSort(int *data, length) {
    int i, j;
    int temp;
    for (i = 0; i < length; i++) {
		for (j = i; j < length; j++) {
			if (a[i] > a[j]) {
				temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
	}
}
时间复杂度:O(n2)最好:O(n2)最坏:O(n2)
## 希尔排序
原理:希尔排序是插入排序排序的一种演进,通过改变每次排序时的步长来提高算法效率。主要是加入了步长的概念,第一次从步长n/2开始,然后一次步长除以2,在每一次步长的元素排序中,使用插入排序,这样就能完成最终的排序。
代码示例:
void shellSort(int *data, int length) {
	int i, j;
	int gap, temp;
	for (gap = length / 2; gap >= 1; gap /= 2) {
		for (i = gap; i < length; i += gap) {
			temp = data[i];
			for (j = i - gap; j >= 0 && temp < data[j]; j-=gap {
				data[j + gap] = data[j];
			}
			data[j + gap] = temp;
		}
	}
}
时间复杂度:O(n3/2)最好:O(nlogn)最坏:O(nlogn)
## 归并排序
原理:归并排序和希尔排序的原理实际相同,都是分而治之的原理。对部分元素先进行排序,然后整合在一起就是一个完整的排好序的数组。首先我们对元素拆分为两大组,然后再拆分,直到只有两个元素为一组。然后两组数据进行比较,将元素从小到大存放到一个临时数组中,结束之后再将四组一个的元素(此时两组元素都是经过两个元素排序的,所以都是有序的)进行排序,同样放到临时数组中,一直反复执行以上操作直到排序完成。从以上思路可以看出,归并排序实际上是可以用递归的思想,解决,拆分之后,再集合。正好和函数的入栈和弹栈相关联。
代码示例:
void sort(int *data, int *temp, int start, int middle, int end {
	int i, j, k;
	i = start;
	j = middle + 1;
	k = 0;
	while (i <= start && j <= middle) {
	    while (data[i] < data[j]) {
			temp[k++] = data[i++];
		}
		while (data[i] > data[j]) {
		    temp[k++] = data[j++];
		}
	}
	while (i <= middle) {
		temp[k++] = data[i++];
	}
	while (j <= end) {
		temp[k++] = data[j++];
	}
	for (i = start; i <= end; i++) {
    	data[i]  =  temp[i];
    }
}

void merge(int *data, int *temp, int start, int end) {
    if (start < end) {
		int middle = start + (end - start) / 2;
		merge(data, temp, start, middle);
		merge(data, temp, middle + 1, end);
		sort(data, temp, start, middle, end);
	}
}

void mergeSort(int *data, int length) {
	int *temp = new int[length];
	if (temp == NULL) {
        return;
    }
	merge(data, temp, 0, length);
}
时间复杂度:O(nlogn)最好:O(nlogn)最坏:O(n)
## 快速排序
原理:快速排序是很有意思的一种排序方式,名称就叫快速排序,想必肯定效率很高了。快速排序主要是使用了哨兵的概念,首先找一个关键字,左边的值比右边的都小,随后再将左右边的数值进行排序以达到整个数组有序的效果。
代码示例:
void sort(int *data, int start, int end) {
    if (start >= end) {
		return;
	}
	int i = start;
	int j = end;
	int key = data[start];
	while (i != j) {
		while (key <= data[j]) {
			j--;
		}
		data[i] = data[j];
		while (key >= data[i]) {
			i++;
		}
		data[j] = data[i];
	}
	data[i] = key;
	sort(data, start, i - 1);
	sort(data, i + 1, end;)
}
void quickSort(int *data, length)
{
    sort(data, 0, length - 1);
}
时间复杂度:O(nlogn)最好:O(nlogn)最坏:O(n2)
以上就是介绍的常用的几种排序算法。如有错误,望大家指正。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值