常见排序算法

1 冒泡排序

双重循环遍历数组,两两比较,并将最大值/最小值交换到最后一位

时间复杂度:\(O(n^{2})\)

空间复杂度:\(O(1)\)

class bubbleSort : public mySort {
public:
	vector<int> callSort(vector<int> nums) {
		cout << "Calling bubbleSort" << endl;
		int n = nums.size();
		for (int i = 0; i < n - 1; i++) {
			for (int j = 0; j < n - 1 - i; j++) {
				if (nums[j] > nums[j + 1]) {
					swap(nums[j], nums[j + 1]);
				}
			}
		}
		return nums;
	}
};

class bubbleSort_v2 : public mySort {
public:
	vector<int> callSort(vector<int> nums) {
		cout << "Calling bubbleSort_v2" << endl;
		int n = nums.size();
		bool swapped = true;
		for (int i = 0; i < n - 1; i++) {
			if (!swapped) {  // 如果某轮没发生任何交换,说明就已经是有序的了
				break;
			}
			swapped = false;
			for (int j = 0; j < n - 1; j++) {
				if (nums[j] > nums[j + 1]) {
					swap(nums[j], nums[j + 1]);
					swapped = true;
				}
			}
		}
		return nums;
	}
};

2 选择排序

双重循环遍历数组,每经过一轮比较,找到最小/最大元素的下标,将其交换之首位。

时间复杂度:\(O(n^{2})\)

空间复杂度:\(O(1)\)

class selectionSort : public mySort {
public:
	vector<int> callSort(vector<int> nums) {
		cout << "Calling selectionSort" << endl;
		int n = nums.size();
		for (int i = 0; i < n - 1; i++) {
			int minIdx = i;
			for (int j = i + 1; j < n; j++) {
				if (nums[j] < nums[minIdx]) {
					minIdx = j;
				}
			}
			swap(nums[i], nums[minIdx]);
		}
		return nums;
	}
};

3 插入排序

在新数字插入过程中,不断与前面的数字比较,直到找到适合自己的位置。

时间复杂度:\(O(n^{2})\)

空间复杂度:\(O(1)\)

3.1 交换法

class insertSort : public mySort {
public:
	vector<int> callSort(vector<int> nums) {
		cout << "Calling insertSort" << endl;
		int n = nums.size();
		for (int i = 1; i < n; i++) {
			int j = i;
			while (j >= 1 && nums[j] < nums[j - 1]) {
				swap(nums[j], nums[j - 1]);
				j--;
			}
		}
		return nums;
	}
};

3.2 移动法

class insertSort_v2 : public mySort {
public:
	vector<int> callSort(vector<int> nums) {
		cout << "Calling insertSort_v2" << endl;
		int n = nums.size();
		for (int i = 1; i < n; i++) {
			int currentNum = nums[i];
			int j = i - 1;
			while (j >= 0 && currentNum < nums[j]) {
				nums[j + 1] = nums[j];
				j--;
			}
			nums[j + 1] = currentNum;
		}
		return nums;
	}
};

快速排序

基本思想: Step1: 从数组中取一个数,称之为基数(pivot),通常取第一个元素; Step2: 遍历数组,将比基数大的数字放到它的左边,比基数小的数字放到它的右边。遍历完成后,数组被分为左右两个区域; Step3: 将左右两个区域视为两个数组,重复前两个步骤,直到排序完成。

时间复杂度:\(O(nlogn)\) 空间复杂度:\(O(logn)\)

class quickSort : public mySort {
public:
	vector<int> callSort(vector<int> nums) {
		cout << "Calling quick sort" << endl;
		quick_sort(nums);
		return nums;
	}
	void quick_sort(vector<int>& arr) {
		int n = arr.size();
		quick_sort(arr, 0, n - 1);
	}

	void quick_sort(vector<int>& arr, int start, int end) {
		// 若区域内的数字少于两个,退出递归
		if (start >= end) return;

		// 将数组分区,获取中间值的下标
		int middle = partition(arr, start, end);

		// 对左边区域进行快排
		quick_sort(arr, start, middle - 1);

		// 对右边区域进行快排
		quick_sort(arr, middle + 1, end);
	}

	// 将arr从start到end进行分区,左边区域比基数小,右边区域比基数大,然后返回中间值的下标
	int partition(vector<int>& arr, int start, int end) {
		// 取第一个数为基数
		int pivot = arr[start];
		// 从第二个数开始分区
		int left = start + 1;
		int right = end;

		while (left < right) {
			// 找到第一个大于基数的位置
			while (left < right && arr[left] <= pivot) {
				left++;
			}
			if (left != right) {
				swap(arr[left], arr[right]);
				right--;
			}
		}

		if (left == right && arr[right] > pivot) {
			right--;
		}

		if (right != start) {
			swap(arr[right], arr[start]);
		}
		return right;
	}
};