300分钟学习笔记-排序问题 冒泡、插入、归并、快排、拓扑

排序算法一般有下面几类常用的
基本排序算法

  • 冒泡排序
  • 插入排序

常考的

  • 归并排序
  • 快速排序
  • 拓扑排序

其他排序算法

  • 堆排序
  • 桶排序

冒泡排序

每一轮,从杂乱的数组头部开始,每两个元素比较大小并交换,直到这一轮中最大活最小的元素被放置在数组的尾部。然后不断重复这个过程,直到所有元素排序好。

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {

        bool hasChange=true;
        for(int i=0;i<nums.size()&&hasChange;i++){//有改变说明这一轮过后可能还没排完
            hasChange=false;
            for(int j=0;j<nums.size()-i-1;j++){
                if(nums[j]>nums[j+1]){
                    int temp=nums[j];
                    nums[j]=nums[j+1];
                    nums[j+1]=temp;
                }
                hasChange=true;
            }

        }
        return nums;

    }
};

空间复杂度
O(1)

时间复杂度

  • 已经排好序的数组:O(n)
  • 完全逆序:O(n^2)
  • 杂乱:平均复杂度:O(n^2)

稳定性:稳定

插入排序

不断将未排序的数插入到已经排好的部分

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {

        for(int i=1;i<nums.size();i++){
            int current=nums[i];//current是待插入的元素

            for(int j=i-1;j>=0&&nums[j]>current;j--){
                nums[j+1]=nums[j];
            }
            nums[j+1]=current;
        }
       
    return nums;

    }
};

时间空间复杂度与冒泡相同

归并排序

分治思想
把一个复杂的问题拆分成若干个子问题进行求解

算法思路
把数组从中间划分为两个子数组
一直递归地将数组划分为更小的子数组,直到数组里只有一个元素
依次按照递归的返回顺序,不断合并排序好的子数组,直到最后把整个数组排序完毕。

class Solution {
public:


	void merge(vector<int>nums ,int lo, int mid, int hi) {
		vector<int> copy = nums;
		//k为合并后数组的下标
		//i为左数组下标
		//j为右数组下标 
		int k = lo, i = lo, j = mid + 1;

		while (k <= hi) {
			if (i > mid) {//左半边都已处理,复制右半边即可
				nums[k++] = copy[j++];
			}
			else if (j > hi) {//右半边都已处理,复制左半边即可
				nums[k++] = copy[i++];
			}
			else if (copy[j] < copy[i]) {//右边的数小于左边的数,拷贝右边的数
				nums[k++] = copy[j++];
			}
			else//左边的数小于右边的数,就拷贝右边的数
				nums[k++] = copy[i++];
		}
	}

	void sort(vector<int> A, int lo, int hi) {
		if (lo >= hi)return;
		int mid = lo + (hi - lo) / 2;
		
		//递归对左右部分排序
		sort(A, lo, mid);
		sort(A, mid + 1, hi);
		merge(A, lo, mid, hi);
	}
};

时间复杂度
对于规模为n的问题,一共要进行log(n)层大小切分;
每一层的合并复杂度都是O(n);
整体的复杂度就是O(nlogn)

空间复杂度 O(n)

稳定性 稳定

快速排序

基本算法思想
也采用分治思想;
把原始数组筛选成较大和较小的两个子数组,然后递归地排序两个子数组。
在分成较小和较大的俩个子数组过程中,如何选定一共基准值尤为关键。

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        sort(nums,0,nums.size()-1);
        return nums;
    }

    int partition(vector<int> &nums, int lo, int hi) {
		//随机选择一个值放到最右边
		int randi= (rand() % (hi - lo + 1)) + lo;
		swap(nums[randi], nums[hi]);

		int i, j;
		for (i = lo, j = lo; j < hi; j++) {
			if (nums[j] <= nums[hi]) {
				swap(nums[i++], nums[j]);//发现j小于基准值就换到左边
			}
		}

		swap(nums[i], nums[j]);//将末尾的基准值放回i
		return i;//返回基准点位置

	}

	void sort(vector<int> &nums, int lo, int hi) {
		if (lo > hi)return;//只剩下一个元素
		
		int p = partition(nums, lo, hi);//找基准点,基准值左边都小于这个数,基准值右边都大于这个数


		sort(nums, lo, p - 1);
		sort(nums, p + 1, hi);

	}

};

最优情况下
即每次基准值都是中间数
T(n)=2*T(n/2)+O(n)
复杂度:O(nlogn)

最坏情况
每次选基准值的时候,都选择了最大或最小值,其中一个的子数组长度为1,另一个之比父数组少1,这样跟冒泡就差不多了。
复杂度:O(n^2)

空间复杂度:O(logn)
在递归过程中,只需要开辟O(1)的空间来交换数组
递归次数为logn,因此它的整体空间复杂度取决于压堆栈的次数。

最经典应用:寻找第k大的数。返回基准值就可以了。时间复杂度为O(n)

在这里插入图片描述

class Solution {
public:
	int findKthLargest(vector<int>& nums, int k) {
        srand(time(NULL));
		return find(nums, 0, nums.size() - 1, nums.size() - k);
	}

	int partition(vector<int>& nums, int lo, int hi) {
		int randi = rand() % (hi - lo + 1) + lo;
		swap(nums[randi], nums[hi]);

		int i, j;

		for (i = lo, j = lo; j < hi; j++) {
			if (nums[j] <= nums[hi]) {
				swap(nums[i++], nums[j]);
			}
		}
		swap(nums[i], nums[hi]);
		return i;
	}

	int find(vector<int> &nums, int lo, int hi, int k) {

		

		int begin = partition(nums, lo, hi);

		if (begin == k) return nums[begin];
		if (begin < k) return find(nums, begin+1, hi, k);//这里+1很重要 不然无法处理元素相同的数组
		if (begin > k) return find(nums, lo, begin-1, k);//-1很重要 同上


		return -1;

	}
};

拓扑排序

应用场合
要将图论里的顶点按照相连的性质进行排序

前提
必须是有向图
图没有环

例:
在这里插入图片描述

得到有向图:
在这里插入图片描述
找每个顶点的入度。看入度为0的点。作为输出结果。删除掉相应的有向边,改变相应节点的入度,再次输出入度为0的节点,消除相应边,重复此过程。

时间复杂度:O(n)
统计顶点的入度需要O(n)的时间
接下来每个顶点被遍历一次,也要O(n) 时间

猜你喜欢

转载自blog.csdn.net/weixin_42189888/article/details/105165530