排序部分专题

各种排序思路总结

/**
 * 冒泡排序 
 * 1 外层循环将排序好的除去
 * 2 内层循环将没排好的数组进行前后比较大小,每经过一个循环,最大的数都在最后面
 * 稳定排序,时间复杂度O(N2)
 * */

/**
 * 选择排序
 *  先找到第一个数后的最小值,并将其与之交换(内层循环为找到最小值)
 * 不稳定,O(N2)
 * */

/**
 * 插入排序
 * 1 外层循环是将排好续的数组保留
 * 2 内层循环是将拿到的数组进行插入
 * 可以是稳定的,O(N2)
 * */

/**
 * 快速排序
 * 递归分治
 * 第一步: 将其划分两个区域 partition
 * 第二分布: 左边递归,右边递归
 * 可以做到稳定 O(NlogN)
 * */

/**
 * 荷兰国旗问题
 * 排序成 左边小,中间相等,右边大的情况
 * 第一步,利用两个指针,一个指向小的部分,一个指向大的部分
 * 第二部分,当前指针遍历数组,如果小鱼目标值将起放到左边,大于放到右边,否则移动下标
 * 快排的一部分,三路快排问题,不稳定 O(NlogN),
 * */

/**
 * 堆排序
 * 第一步:建立大根堆,当前节点的大于父节点时,将其与之交换,向上调整
 * 第二步:将0位置的数与最后的位数交换,即根节点与尾节点交换
 * 第三步:做heapify向下调整:找到当前节点与左右子节点的最大值,交换后向下延伸
 * 不稳定排序 O(N)
 * */

/**
 * 归并排序
 * 第一步:找到中点
 * 第二步 : 递归左右子数组
 * 第三步: 合并:此时分为三部分,先理好一遍没有的,再理好一边有的
 * 稳定  O(NlogN)
 * */

  具体代码实现部分

//
// Created by yzm on 11/8/18.
//

#include "sort.h"
#include <stdlib.h>

/**
 * 冒泡排序
 * 1 外层循环将排序好的除去
 * 2 内层循环将没排好的数组进行前后比较大小,每经过一个循环,最大的数都在最后面
 *
 * */


void sort::bubbleSort(vector<int> &arr) {

    if(arr.size() == 0||arr.size() == 1)
        return;
//    for(int i = 0 ;i < arr.size(); i++)
//        for(int j = i + 1; j < arr.size(), j++)
//        {
//            if(arr[i] > arr[j])//此处是稳定的排序
//                swap(arr,i,j);
//        }
    for( int i = arr.size()-1; i > 0 ; i--)
        for( int j = 0; j < i ; j++)
        {
            if(arr[j] > arr[j+1])//此处是稳定的排序
                swap(arr,j,j+1);
        }//第一层下来最大的值已经冒泡到最上面的部分
    return;
}
/**
 * 选择排序
 *  先找到第一个数后的最小值,并将其与之交换(内层循环为找到最小值)
 *
 * */
void sort::selecttSort(vector<int> &arr) {
    if(arr.size()==0||arr.size()==1)
        return;
    for(int i = 0; i < arr.size(); i++) {
        int min = i;
        for (int j = i + 1; j < arr.size(); j++) {

            min = arr[min] < arr[j]? min : j;//找最小值,此时不是稳定排序的
        }
        swap(arr,i,min);
    }
    return;
}
/**
 * 插入排序
 * 1 外层循环是将排好续的数组保留
 * 2 内层循环是将拿到的数组进行插入
 *
 * */
void sort::insertSort1(vector<int> &arr) {
    if (arr.size() == 0 || arr.size() == 1)
        return;
    for (int i = 1; i < arr.size(); i++) {

//        for(int j = i ; j > i ;j--)
//            if(arr[i--] > arr[j])//可以实现稳定排序
//                swap(arr,i,j);
        //打牌,先找位置,找到了吧位置换过去
        for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
            swap(arr, j, j + 1);//此处会认为是冒泡排序:冒泡排序的每一轮是相邻两个数进行比较,这个是每轮一个数和前已经有序的进行比较
        }
    }

    return;
}

/**
 * 直接插入排序,先挪位置直接插入
 *
 * */
void sort::insertSort2(vector<int> &arr) {
    int i,j;
    for(i=1;i<arr.size();i++)
    {
        int temp=arr[i];
        for(j=i;j>0&&arr[j-1]>temp;--j)
            arr[j]=arr[j-1];
        arr[j]=temp;
    }
}
/**
 * 快速排序
 * 递归分治
 * 第一步: 将其划分两个区域 partition
 * 第二分布: 左边递归,右边递归
 * 可以做到稳定 O(NlogN)
 * */
void sort::quickSort1(vector<int> &arr,int L, int R) {
    cout << L << "初始参数  "<<R<<endl;
    if(L < R)
    {
        vector<int> p = partition(arr,L,R);
        int left =  p[0] - 1;//不能作为左值
        int right = p[1] + 1;
        cout<<p.size()<<"   "<< left << "  "<< right<<endl;
        quickSort1(arr, L , left);
        quickSort1(arr,right,R);
    }

}
/**
 * 荷兰国旗问题
 * 排序成 左边小,中间相等,右边大的情况
 * 第一步,利用两个指针,一个指向小的部分,一个指向大的部分
 * 第二部分,当前指针遍历数组,如果小鱼目标值将起放到左边,大于放到右边,否则移动下标
 * 快排的一部分,不稳定 O(NlogN)
 * */

vector<int> sort::netherlandSort(vector<int> &arr, int L, int R, int target) {

    int less = L-1;
    int more = R+1;
    int cur = L;
        while (cur < more) {
            if (arr[cur] < target) {
                swap(arr, ++less, cur++);
            } else if (arr[cur] == target) {
                cur++;
            } else {
                swap(arr, cur, --more);
            }
        }
    vector<int> a = {less+1,more-1};
    return a;
}

//随机快速排序
void sort::quickSort2(vector<int> &arr, int L, int R) {
    if(L < R)
    {
        int randomNum = L + rand()%(R - L + 1);//此处右边的表达是又不能做左值
        swap(arr,randomNum,R);//产生随机数
        vector<int> p = partition(arr,L,R);
        int left =  p[0] - 1;//不能作为左值
        int right = p[1] + 1;
        quickSort2(arr, L , left);
        quickSort2(arr,right,R);
    }
}

/**
 * 堆排序
 * 第一步:建立大根堆,当前节点的大于父节点时,将其与之交换,向上调整
 * 第二步:将0位置的数与最后的位数交换,即根节点与尾节点交换
 * 第三步:做heapify向下调整:找到当前节点与左右子节点的最大值,交换后向下延伸
 * 不稳定排序 O(N)
 * */
void sort::heapSort(vector<int> &arr) {
    if(arr.size()==0||arr.size()==1)
        return;
    //第一步:建立大根堆
    for(int i = 1; i < arr.size(); i++){
        heapInsert(arr,i);
    }
    //第二步:将0位置的数与最后的位数交换,即根节点与尾节点交换
    int heapSize = arr.size();
    swap(arr , 0, --heapSize);
    //做heapify调整
    while(heapSize > 0){
        heapify(arr, 0, heapSize);
        swap(arr, 0, --heapSize);//每次将堆中最后位置的数与o位置的数进行交换
    }
}


/**
 * 归并排序
 * 第一步:找到中点
 * 第二步 : 递归左右子数组
 * 第三步: 合并:此时分为三部分,先理好一遍没有的,再理好一边有的
 * 稳定  O(NlogN)
 * */

void sort::mergeSort(vector<int> &arr,  int &L, int &R) {
    if (L == R)
        return;
        int mid = L + ((R - L) >> 1);

        mergeSort(arr, L, mid);
        int lr = mid + 1;
        mergeSort(arr, lr, R);
        merge(arr, L, mid, R);//相等的先拷贝左边的,此时是稳定的
}



void sort:: swap(vector<int> &arr,  const int &i,const  int &j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
    return;
}

void sort::merge(vector<int> &arr,int &L,int &mid, int &R) {
/*
 * 关于此函数遇到的问题
 * 数组下表赋值必须提前分配数组空间,如果没有提前分配空间就必须使用push_back
 * 这是因为push_back会自动new,new出来的会保存在堆上,否自在全栈上
 * */
    vector<int> help(R - L + 1);
    //vector<int>help;//此时的数组大小为空 因此help[i]没有任何意义
    int k = 0;
    int i = L ;
    int j = mid +1;
    while (i <= mid&&j <= R)
    {

//        if( arr[i] < arr[j])
//            help[k++] = arr[i++];
//        else
//            help[k++] = arr[j++];
        help[k++] =  arr[i] < arr[j] ?  arr[i++] : arr[j++];
        //help.push_back(arr[i] < arr[j] ?  arr[i++] : arr[j++]);
    }

    while (i <= mid) {
        help[k++] = arr[i++];
        //help.push_back(arr[i++])
    }
    while (j <= R) {
        help[k++] = arr[j++];
        //help.push_back(arr[j++])
    }
    for (k = 0; k < help.size(); k++) {
        arr[L + k] = help[k];
    }
}

vector<int> sort::partition(vector<int> &arr, int L, int R) {
    int less = L - 1;
    int more = R ;

    while (L < more) {
        if (arr[L] < arr[R]) {
            swap(arr, ++less, L++);
        } else if (arr[L] == arr[R]) {
            L++;
        } else {
            swap(arr, L, --more);
        }
    }
    swap(arr, more, R);
    vector<int> a = {less+1,more};

    return a;
}
/**
 * 建立大根堆程序
 * 当前节点的大于父节点时,将其与之交换
 *
 * */
void sort::heapInsert(vector<int> &arr, int index) {
    while (arr[index] > arr[(index - 1)/2]){//当该节点的函数大于父节点时,将其与父节点进行交换
        int temp = (index -1)/2;
        swap(arr, index, temp);
        index = temp;//向上走
    }

}

void sort::heapify(vector<int> &arr, int index, int size) {
    int left = index * 2 +1;//左子节点
    while(left < size){//如果左节点存在
        int largest = left +1 < size && arr[left + 1] > arr[left] ? left + 1 : left;//如果右节点存在,找到左右节点的最大值
        largest = arr[largest] > arr[index] ? largest : index;//找到该节点与子节点中最大值的部分
        if (largest == index){//如果子节点相等则跳出循环
            break;
        }
        swap(arr, index ,largest);//将最大值放在该节点上
        index = largest;
        left = index * 2 + 1;//向下继续延伸下去
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40028201/article/details/84567678
今日推荐