希尔排序是直接插入排序的升级;堆排序是简单选择排序的升级;
快速排序是冒泡排序的升级,它们都属于交换排序;
冒泡排序(Bubble Sort)的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序为止。
流程:
第1趟冒泡:将第1个元素和第2个元素进行比较,若为反序,则将两个元素交换,然后比较第2个元素和第3个元素。依次类推,直到第 n-1个元素和第 n个元素进行比较为止。其结果使最大值元素被放置在最后一个位置(第 n个位置)。
第2趟冒泡:对前 n-1个元素进行同样操作,其结果是使第二大元素被放置在倒数第二个位置上(第 n-1个位置)。
……
第n-1趟冒泡:将第1个元素和第2个元素进行比较,若为反序,则将两个元素交换。
完成全部记录的排序。
vector<int> bubbleSort(vector<int> list) {//冒泡排序
vector<int> result;
if (list.empty()) {
return result;
}
result = list;
int temp;
for (int i = 0; i < result.size() - 1;++i) {// 要遍历的次数
bool bChanged = false;//交换标志位
for (int j = 0; j < result.size() - 1 - i;j++) {//从后向前依次的比较相邻两个数的大小
if (result[j+1]<result[j]) {//如果后面的元素小,则交换它们的位置
temp = result[j + 1];
result[j + 1] = result[j];
result[j] = temp;
bChanged = true;
}
}
if (false == bChanged) {//如果标志为false,说明本轮遍历没有交换,已经是有序数列,可以结束排序
break;
}
}
return result;
}
快速排序(Quick Sort)的基本思想是:通过一趟排序,将待排序记录分割成独立的两部分,其中一部分记录的关键字都比另一部分记录的关键字小,然后继续按此方法分别对这两部分记录进行排序,持续递归,直到整体有序。
流程:
第1步:设定一个分界值,通过该分界值将数组分成左右两部分。(通常选取待排序第一个记录的关键字,也可以取左后一个,或者中间位置等等)
第2步:将大于等于分界值的记录放到序列右边;将小于等于分界值的记录放到序列左边;
第3步:对左边的子序列递归进行第1、2步的操作;对右边的子序列也递归进行第1、2步的操作。
……
直到完成所有子序列的递归就完成了全部记录的排序。
int division(vector<int> &list, int left, int right) {//快速排序的division函数
int base = list[left];// 以最左边的数(left)为基准(通常就是选取第一个元素)
while (left < right) {
while (left < right && list[right] >= base)//从序列右端开始,向左遍历,直到找到小于base的数
right--;
list[left] = list[right];// 找到了比base小的元素,将这个元素放到左边的位置
while (left < right && list[left] <= base)// 从序列左端开始,向右遍历,直到找到大于base的数
left++;
list[right] = list[left];//找到了比base大的元素,将这个元素放到右边的位置
}
list[left] = base;// 最后将base放到left位置。此时,left位置的左侧数值应该都比left小,而left位置的右侧数值应该都比left大
return left;
}
void quickSort(vector<int> &list, int left, int right) {// 快速排序
if (left < right) {// 左下标一定小于右下标,否则就越界了
int base = division(list, left, right);// 对数组进行分割,取出下次分割的基准标号
quickSort(list, left, base - 1);// 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序
quickSort(list, base + 1, right);// 对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序
}
}