八大排序算法

1. 冒泡排序

依次两两比较,如果大就交换,所以最后面会保存到较大值(或较小值),然后再进行新一轮的比较,所以比较轮数是length-1,每一轮比到第length-i-1项(因为后面的都比较完了)

public static void bubbleSort(int[] arr) {
		for(int i =0;i<arr.length-1;i++) {
			for(int j=0;j<arr.length-1-i;j++) {
				int temp;
				if(arr[j]>arr[j+1]) {  //升序
					temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}
			}
		}
	}

2. 快速排序

思想:找出一个标准数,以此数为基准,将序列分为两部分,前面是小于等于这个数的数,后面是大于这个数的数,再将这两部分再做类似的操作,即可以使用递归的思想
步骤:
取第一个数为标准数
然后记录排序标志low,high
循环找出比标准数大的数和比标准数小的数,分成前面部分和后面部分
先从右边数开始
如果右边的数字比标准数大,标志前移,否则就用右边的数字替换左边的数字
替换了之后就从左边开始比
如果左边的数字比标准数小,标志后移,否则,就用左边的数替换右边的数
把标准数赋值给所在低位置的元素,注意,此时低位置和高位置重合
递归处理小的那部分数字
递归处理大的那部分数字

 public static void quickSort(int[] arr, int start, int end) {
		if(start<end) {
			//把数组中的第0个数字作为标准数
			int stard = arr[start];
			//记录需要排序的下标
			int low = start;
			int high = end;
			//循环找出比标准数大的数和比标准数小的数,分成前面部分和后面部分
			while(low<high) {
				//右边的数字比标准数大,标志前移
				while(low<high && stard<=arr[high]) {
					high--;
				}
				//如果右边的数字比标准数小,就用右边的数字替换左边的数字
				arr[low] = arr[high];
				//替换了之后就从左边开始比
				//如果左边的数字比标准数小,标志后移
				while(low<high && arr[low] <= stard) {
					low++;
				}
				//否则,就用左边的数替换右边的数
				arr[high] = arr[low];			
			}
			//把标准数赋值给所在低位置的元素,注意,此时低位置和高位置重合
			arr[low] = stard;
			//递归处理小的那部分数字
			quickSort(arr,start,low);
			//递归处理大的那部分数字
			quickSort(arr,low+1,end);
		}
}		

3. 插入排序

插入排序思想:从第二个开始,依次和前面的元素进行比较,如果当前元素比前一个小就交换,依次进行就把前面的元素变成有序的了。然后在从第三个、第四个依次下去
步骤:
从第二个元素开始遍历所有元素
如果当前元素比前一个数字小,就把当前元素保存到临时变量中
再去遍历当前数字前面的所有数字,所以j从i-1开始
如果j>=0 && temp<arr[j],把前一个数字赋给后一个数字
两种情况结束循环:
1.j=-1
2.当前面的数字已经比temp小时,就不会把前一个数字赋给后一个数字,而是把temp赋给后一个数字

void dselect(vector<int>& input) {
    int len = input.size();
    for (int i = 1; i < len; i++) {
        int temp = input[i];
        if (input[i] < input[i - 1]) {
            int j = i - 1;
            for (; j >= 0 && temp < input[j]; j--) {
                input[j + 1] = input[j];
            }
            input[j + 1] = temp;
        }
    }
}

4. 希尔排序

希尔排序思想:引入步长,length/2,将序列依据步长分组,将每一组依次采用直接插入排序
采用步长思想可以快速将大的值移到后面,将小的值移到前面。

void xierSort(vector<int>& input){
        int len = input.size();
        for(int d=len/2;d>0;d/=2){  //遍历所有的步长
            for(int i=d;i<len;i++){  //从中间开始遍历所有组的元素
                for(int j=i-d;j>=0;j-=d){ //遍历本组的所有元素
                    if(input[j+d]<input[j]){  //如果当前元素大于加上步长的那个元素,就交换
                        int temp = input[j];
                        input[j]=input[j+d];
                        input[j+d]=temp;
                    }
                }
            }
        }
    }

5. 选择排序:

选择排序思想:
先假设第一个为最小值,将于后面所有元素比较,如果有比它更小的数,就更新最小值下标,然后再把它交换,放到最前面,然后标志位++,把第二个当成最小值,将它和后面的比较。。。。
这样,最前面的都是依次从小到大好了的了。

public static void selectSort(int[] arr) {
		//遍历所有的元素
		for(int i=0;i<arr.length;i++) {
			//每一轮的标志位,默认第一个元素时最小值
			int minIndex = i;
			//把当前定义的的最小数和后面的数依次比较,并记录较小数的下标
			for(int j=i+1;j<arr.length;j++) {
				if(arr[minIndex]>arr[j]) {
					minIndex = j;
				}
			}
			
			//如果找到的minIndex还是原来的,即等于i,就不用交换
			//如果不是,就交换,把找到的最小值放到最前面
			if(i!=minIndex) {
				int temp = arr[i];
				arr[i] = arr[minIndex];
				arr[minIndex] = temp;
			}
		}
		
	}

6. 归并排序

归并排序思想:
归并方法可以将两个有序序列排序,所以要将一个序列排序,就不断将这个序列分成两部分,直到每部分只有一个元素,因为一个元素的序列可以认为是有序数列,在进行归并,实现排序,不断递归就可以实现。

//还是用数组来实现,先把vector存到数组里面进行
class Solution {
public:
    void merge(int a[],int* left,int leftlen,int* right,int rightlen){
        int i=0,j=0,k=0;
        while(i<leftlen && j<rightlen){
            if(left[i]<right[j]){
                a[k++]=left[i++];
            }else{
                a[k++]=right[j++];
            }
        }
        
        while(i<leftlen){
            a[k++]=left[i++];
        }
        
        while(j<rightlen){
            a[k++]=right[j++];
        }
    }

    void mergeSort(int a[],int n){
        int mid = n/2;
        if(n<2) return;
        int* left = new int[mid];
        int* right = new int[n-mid];
        
        for(int i=0;i<mid;i++){
            left[i]=a[i];
        }
        for(int i=mid;i<n;i++){
            right[i-mid]=a[i];
        }
        
        mergeSort(left,mid);
        mergeSort(right,n-mid);
        merge(a,left,mid,right,n-mid);
        
        delete[] left;
	    delete[] right;
    }

    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int len = input.size();
        vector<int> array;
        if (len == 0 || k == 0 || k > len) return array;
        
        int* a = new int[len];
        for(int i=0;i<len;i++){
            a[i]=input[i];
        }
        
        mergeSort(a,len);
        
        for (int i = 0; i < k; i++) {
            array.push_back(a[i]);
        }

        return array;
    }
};
//用vector实现的归并算法

void MergeSortHelp(vector<int>& data, vector<int>& copy, int start, int end) {
    if (start == end)
        return;
    int mid = (start + end) / 2;
    MergeSortHelp(copy, data, start, mid);  
    //不太懂这里的操作,每一次归并排序后的值又到了data中保存
    //下面都还是再copy中,这个时候copy得到的是上一次归并后的值,即上一次data的值
    //不太明白这个操作,好像指针一样。
    MergeSortHelp(copy, data, mid + 1, end);
    int i = start, j = mid + 1;
    int index = start;

    while (i <= mid && j <= end) {
        if (data[i] < data[j])
            copy[index++] = data[i++]; //从小到大
        else
            copy[index++] = data[j++];//从小到大
    }

    while (i <= mid)
        copy[index++] = data[i++];

    while (j <= end)
        copy[index++] = data[j++];
}

vector<int> MergeSort(vector<int>& v) {
    bool Invalid_Input = false;
    vector<int>copy;
    int len = v.size();
    if (len <= 0) {
        Invalid_Input = false;
        return copy;
    }

    for (int i = 0; i < len; i++)
        copy.push_back(v[i]);

    MergeSortHelp(v, copy, 0, len - 1);
    return copy;
}


vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
    int len = input.size();
    vector<int> array;
    if (len == 0 || k == 0 || k > len) return array;

    int start = 0;
    int end = len - 1;
    vector<int> res;
    res = MergeSort(input);

    for (int i = 0; i < k; i++) {
        array.push_back(res[i]);
    }

    return array;
}

int main() {
    vector<int> invec{ 1, 2, 3, 7, 5, 9, 0, 11, 15, 8, 30, 20, 19 };
    //vector<int> *p = new int[]{1, 2, 3, 7, 5, 9, 0, 11, 15, 8, 30, 20, 19};
    vector<int> res;
    
    res=GetLeastNumbers_Solution(invec, 4);



    for (auto& i : res) {
        cout << i << " ";
    }
    cout << endl;
}

7. 基数排序

基数排序思想:适合有很大的数字,也有很小的数字
{512,2,45,67,897,56,89,112,33,156,342}
根据个位、十位、百位上的数来排序,创建10个桶0~9,因为每个位上的数字必是其中之一,
桶可以用一个二维数组、队列实现
第一轮,先从个位,将数组中的数放入个位数对应的桶中,再依顺序存回arr
第二轮,再从十位,将数组中的数放入个位数对应的桶中,再依顺序存回arr
。。。。。

class Solution {
public:
    
    void radixSort(vector<int>& input){
        int len = input.size();
        int max=0;
        for(int i=0;i<len;i++){
            if(input[i]>max){
                max=input[i];
            }
        }
        
        int maxlen=1;
        while(max/10){
            maxlen++;
            max/=10;
        }
        
        queue<int> que[10];
        
        for(int i=0,n=1;i<maxlen;i++,n*=10){
            for(int j=0;j<len;j++){
                int tonIndex=input[j]/n%10;
                que[tonIndex].push(input[j]);
            }
            int inputIndex=0;
            for(int k=0;k<10;k++){
                while(!que[k].empty()){
                    input[inputIndex]=que[k].front();
                    que[k].pop();
                    inputIndex++;
                }
            }
        }
        
    }

    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int len = input.size();
        vector<int> array;
        if (len == 0 || k == 0 || k > len) return array;
        
        radixSort(input);
        
        for (int i = 0; i < k; i++) {
            array.push_back(input[i]);
        }

        return array;
    }
};

8. 堆排序

大顶堆:父节点的值大于子节点的值,升序排列
把一个顺序存储的二叉树改成一个大顶堆,然后把根节点的权和最后一个叶子节点的权值交换,然后把最后叶子节点的值取出存放,这样就取出一个最大值
然后再把新的堆变成一个大顶堆

public static void heapSort(int[] arr) {
		//开始位置为最后一个非叶子节点,即最后一个节点的父节点
		//int start = (arr.length-1)/2;
      int start = arr.length/2-1;
		//从最后一个非叶子节点开始,依次往前遍历非叶子节点,
		//将非叶子节点与其两个子节点比较,调整为大顶堆
		for(int i=start;i>=0;i--) {
			maxHeap(arr,arr.length,i);
		}
		//堆排序完了
		//先把数组中的第0个元素和第一个交换,这样就是第0个元素比下面的子节点大,
		//所以直接从0节点开始,把新的堆变为为大顶堆
		for(int i=arr.length-1;i>0;i--) {
			int temp = arr[0];
			arr[0] = arr[i];
			arr[i] = temp;
			maxHeap(arr,i,0);
		}
	}
	
	public static void maxHeap(int[] arr, int size, int index) {
		//左子节点
		int leftIndex =2*index+1;
		//右子节点
		int rightIndex =2*index+2;
	    int max = index;
		//和两个子节点比较,a找出最大的节点
		if(leftIndex<size && arr[leftIndex]>arr[max]) {
			max = leftIndex;
		}
		if(rightIndex<size && arr[rightIndex]>arr[max]) {
			max = rightIndex;
		}
		
		//交换位置
		if(max!=index) {
			int temp = arr[index];
			arr[index] = arr[max];
			arr[max] = temp;
			//交换之后可能会破坏之前拍好的堆,所以,之前拍好的堆要重新调整
			maxHeap(arr,size,max);
		}
	}

堆排序查找最大的k的数

class Solution {
public:
    
    void radixSort(vector<int>& input){
        int len = input.size();
        int max=0;
        for(int i=0;i<len;i++){
            if(input[i]>max){
                max=input[i];
            }
        }
        
        int maxlen=1;
        while(max/10){
            maxlen++;
            max/=10;
        }
        
        queue<int> que[10];
        
        for(int i=0,n=1;i<maxlen;i++,n*=10){
            for(int j=0;j<len;j++){
                int tonIndex=input[j]/n%10;
                que[tonIndex].push(input[j]);
            }
            int inputIndex=0;
            for(int k=0;k<10;k++){
                while(!que[k].empty()){
                    input[inputIndex]=que[k].front();
                    que[k].pop();
                    inputIndex++;
                }
            }
        }
        
    }

    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int len = input.size();
        vector<int> array;
        if (len == 0 || k == 0 || k > len) return array;
        
        radixSort(input);
        
        for (int i = 0; i < k; i++) {
            array.push_back(input[i]);
        }

        return array;
    }
};

复杂度比较

在这里插入图片描述

稳定性分析:
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法
详细分析请参考此博文

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值