1.冒泡排序
思想
冒泡排序的思想是不断比较相邻元素,把大的或者小的放到后面,这样第一次最大的或者最小的元素就会在序列最后,第一轮结束之后,最后一个元素是最值元素,不用参与排序,所以第二次循环只需比较到倒数第二个元素即可,由于每次比较,待排列中最值元素都会被排到后面,就像水中的气泡一样漂浮上来,故得此名。
代码
#include <iostream>
using namespace std;
/**
*排序
*/
void bubbling_sort(int num[], int length);//冒泡排序
int main() {
int number[10] = { 12,234,45,23,56,45,35,234,567,4 };
int length;
length = sizeof(number) / sizeof(int);
bubbling_sort(number,length);
return 0;
}
//冒泡排序
void bubbling_sort(int num[], int length) {
int i, j, temp;
temp = 0;
for (i = 0; i < length - 1; i++) {
for (j = 0; j < length - 1 - i; j++) {
if (num[j] > num[j + 1]) {
temp = num[j];
num[j] = num[j + 1];
num[j + 1] = temp;
}
}
}
for (int k = 0; k < length; k++) {
cout << num[k] << endl;
}
}
复杂度分析
空间复杂度:由于是在原序列上进行排序,所以空间复杂度为O(1);
时间复杂度:嵌套循环,一共两次循环,时间复杂度为O(n*n);
稳定性:稳定性指的是会不会改变相对位置,比如[1,4,,3,5,4],会不会改变两个4的相对位置,由于冒泡比较的是两个相邻元素,所以稳定。
2.选择排序
思想
选择排序的思想就是第一轮找出最小的元素和第一个位置进行数值互换,第二轮第二小元素和第二个位置进行数值互换…如此直至排序结束。
代码
//选择排序
void select_sort(int* num, int length) {
int i, j, min, temp;
temp = 0;
for (i = 0; i < length-1; i++) {
min = i;
for (j = i + 1; j < length; j++) {
if (num[j] < num[min]) {
min = j;
}
if (min != i) {
temp = num[min];
num[min] = num[i];
num[i] = temp;
}
}
}
cout << "选择排序:" << endl;
for (int k = 0; k < length; k++) {
cout << num[k] << endl;
}
}
复杂度分析
空间复杂度:在原序列上进行排序,没有开辟新空间,复杂度为O(1);
时间复杂度:需要两次循环遍历,复杂度为O(n*n);
稳定性:没有交换相对位置,稳定。
3.插入排序
思想
插入排序默认第一个元素是有序的,然后每次将有序元素列后面一个元素插入进有序元素列表,直至结束,排序完毕。
代码示例
//插入排序
void insert_sort(int* num, int length) {
int temp = 0;
for (int i = 1; i < length; i++) {//默认第一个有序,所以循环n-1次
for (int j = 0; j < i; j++) {
if (*(num + i) < *(num + j)) {
temp = *(num + i);
*(num + i) = *(num + j);
*(num + j) = temp;
}
}
}
cout << "插入排序" << endl;
for (int k = 0; k < length; k++) {
cout << *(num + k) << endl;
}
}
复杂度分析
空间复杂度:在原有序列上进行排序,没有开辟新空间,空间复杂度为O(1);
时间复杂度:进行两次循环遍历,时间复杂度为bO(n*n);
稳定性:没有改变相同大小元素相对位置,稳定。
4.希尔排序
思想
希尔排序是插入排序的升级版,以步长2为例,先将待排序数个数为n的数列分为n/2组,每组数字为原数字序列基础上间隔n/2个数字,例如 【2,3,45,3,6,23,45,4,3,67】,分组后为【2,23】【3,45】 【45,4】 【3,3】 【6,67】,分组之后对每一组进行排序,(排序过程是逻辑上的,不开辟新空间),排序之后为【2,3,4,5,6,23,45,45,3,67】;进行下一次循环,再次分割,将n个数字分为(n/2)/2组,即分为5/2=2组,【2,4,6,45,3】 【3,5,23,45,67】,排序之后为【2,3,3,5,4,23,6,45,45,67】最后将该数组进行插入排序即可。
代码
//希尔排序
void shell_sort(int* num, int length) {
int i, j, k, gap, temp;
temp = 0;
for (gap = length / 2; gap > 0; gap /= 2) {//步长2为例
for (i = 0; i < gap; i++) {//进行分组
for (j = i + gap; j < length; j += gap) {//每一组逻辑上的相邻元素
if (num[j] < num[j - gap]) {//每组逻辑上相邻元素比较
temp = num[j];
k = j - gap;
while (k >= 0 && num[k] > temp) {//如果逻辑上前一个元素比后一个元素大,则将该组相应元素后移逻辑上一位
num[k + gap] = num[k];
k = k - gap;
}
num[k + gap] = temp;//进行插入操作
}
}
}
}
cout << "希尔排序" << endl;
for (int k = 0; k < length; k++) {
cout << *(num + k) << endl;
}
}
复杂度分析
空间复杂度:在原有序列上进行排序,没有开辟新空间,复杂度为O(1);
时间复杂度:过程类似二分,重复n次,复杂度为O(nlogn);
稳定性:由于将元素进行了分组排序操作,可能改变相同大小元素相对位置,所以不稳定。
5.快速排序
思想
快速排序思想就是选择一个数字作为支点,将小于该数字的元素放在左边,大于该数字的元素放在该数字右边,下一次将左右两边再各选一个支点进行该过程,直至最后排序完毕。
代码示例
//快速排序
void quick_sort(int num[], int length) {
int left, right,key;
left = 0;
right = length - 1;
key = num[0];
if (length > 1) {//长度等于1时不必再排序
while (left < right) {
for (; right > left; right--) {
if (num[right] < key) {
num[left] = num[right];
break;
}
}
for (; left < right; left++) {
if (num[left] > key) {
num[right] = num[left];
break;
}
}
}
num[left] = key;
quick_sort(num, left);
quick_sort(num + left + 1, length - left - 1);
}
}
复杂度分析
空间复杂度:排序过程是在原序列上,但是在递归过程中需要保存数据,所以空间复杂度范围是O(logn)~O(n);
时间复杂度:分组递归,时间复杂度为O(nlogn);
稳定性:排序时可能调换相同大小元素相对位置,故不稳定。