快速排序和堆排序要点记录

声明:本文资料来自于 牛客网(算法初级笔记2)

/*
 题目1:
 给定一个数组arr,和一个数num,请把小于等于num的数放在数 组的左边,大于num的数放在数组的右边。
 思路:两个指针,一个less,一个cur,碰到大于num的,cur指针前移,less不动
 碰到小于等于num的,less的下一个指针和cur交换,less和cur 都 自增 1
 */
class niukeClass_1 {
    void swap(vector<int>arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    vector<int> partition(vector<int>&arr,int num){
        if(arr.size()==0)return arr;
        int less = -1;
        int cur=arr[0];
        while (cur<arr.size()) {
            if(arr[cur]<=num){
                swap(arr, ++less, cur++);
            }
            else {
                cur++;
            }
        }
        return arr;
    }
    
};
/*
 题目二 :荷兰国旗
 给定一个数组arr,和一个数num,请把小于num的数放在数组的 左边,
 等于num的数放在数组的中间,大于num的数放在数组的 右边。
 要求额外空间复杂度O(1),时间复杂度O(N)
 思路:
 1 设置一个起始位置的左边的一个变量less,用于记录小于num的范围坐标
 2 设置一个最大位置的右边的一个变量more,用于记录大于num的范围坐标
 3 设置一个当前的指针,用于遍历当前数组的值
 4如果当前cur的值小于p,当前位置和less的下一个值交换,然后less++,cur++
 5如果当前的cur的值大于p,当前位置和more的上一个位置交换,然后交换之后的cur继续执行步骤4
 6 如果当前的cur的值等于p,cur++
 */
class  niukeClass_2 {
    void swap(vector<int>&arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    /*
     参数1:数组
     参数2:数组的左边界
     参数3:数组的右边界
     参数4:num
     返回值: 等于p的左边界坐标和右边界坐标
     */
    vector<int> partition(vector<int>&arr,int l,int r,int p){
        int less = l-1;
        int more = r+1;
        int cur = l;
        while (cur<more) {
            if(arr[cur]<p){
                swap(arr, ++less, cur++);
            }
            else if(arr[cur]>p){
                swap(arr,--more,cur);//cur不加的原因是,还要走上一个if
            }
            else {
                cur++;
            }
        }
        vector<int>vec;
        vec.push_back(less+1);
        vec.push_back(more-1);
        return vec;
    }
};
/*
 题目三:
 随机快速排序
 
 经典快排缺点:
 1 以数组最后一个元素num为参照,小于等于num的放左边,大于num的放右边,每次只能确定一个位置
 2 [654321]的数组,以1开始,这样每次分的右边为空,时间复杂度为O(n^2)
 改进:
  1 用 随机坐标作为 num,这样快排的最坏时间复杂度就是概率问题了,平均为 O(NlogN)
  2 用荷兰国旗问题改进快排,每次排完之后,中间为所有等于num的数,这样 这些数就不用在对比了,常数计算快一些
 
问题:快排的额外空间复杂度 logN
原因: 每二分一次,都需要记录中间的断点位置,这样弄完左边之后,才能根据断点找到右边继续递归,也就是说每二分一次,就需要一个断点,那么 总共二分了logN,所以额外空间负责度为O(logN)
 但是如果类似于 1234567,断点第一次打在7,第二次6。。,这样空间负责度就会变为 O(n),所以最快情况下为O(n)
 这也是个概率问题,长期期望值 为 O(logN)
 */

class niuheclass_3{
public:
    void swap(vector<int>&arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    } //9   6 12 16 7 20 5 1
    vector<int> partition(vector<int>&arr,int l,int r){
        int less = l-1;
        int more = r+1;
        int cur = l;
        int p = arr[r];//把最后一个值作为分界值
        while (cur<more) {
            if(arr[cur]<p){
                swap(arr, ++less, cur++);
            }
            else if(arr[cur]>p){
                swap(arr,--more,cur);//cur不加的原因是,还要走上一个if
            }
            else {
                cur++;
            }
        }
        vector<int>vec;
        vec.push_back(less+1);
        vec.push_back(more-1);
        return vec;
    }
    
    void quickSortSub(vector<int>&arr,int l ,int r){
        if(l<r){
            //选中随机的坐标,然后和最后一个坐标交换
            int randomPosition =l+(int)( (rand() % (999 + 1) / (float)(999 + 1)) * (r-l+1));
            swap(arr,randomPosition,r);
            vector<int>vec = partition(arr, l, r);
            quickSortSub(arr, l, vec[0]-1);
            quickSortSub(arr, vec[1]+1, r);
        }
    }
    void quickSort(vector<int>&arr){
        if(arr.size()<2){
            return;
        }
        quickSortSub(arr, 0, (int)arr.size()-1);
    }

};
/*
 题目三:建立大根堆的过程
 问题: 建立大顶堆的时间复杂度
 答案:
 每一个节点插进来的时候都与已经形成的二叉树的高度有关,有n个节点,高度就为logN
 第一个节点插件来就是log1,第二个节点就是log2.。。 第n-1个节点就是logn-1
 所以 log1 + log2 +。。。+logN-1 = O(N)
 */
class niukeClass_3 {
    void swap(vector<int>&arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    /*
     参数1:数组
     参数2:数组的第几个元素
     思路:
     每次插入的时候,和他的父节点进行比较,如果大于父节点,和父节点交换为孩子,
     然后父节点接着和父节点的父节点比较,直到小于等于为止(顶点元素是相等的,所以条件会终止)
     父节点的位置 = (当前节点的位置-1)/ 2
     */
    void heapInsert(vector<int>arr,int index){
        while (arr[index]>arr[(index-1)/2]) {
            swap(arr, index, (index-1)/2);
            index = (index-1)/2;
        }
    }
};
/*
 题目4: 调整大顶堆中某一个元素
 思路:
   当修改大顶堆中某一个位置的元素的时候,该元素a和他的左右子树中较大的值b比较,如果a<b,a和b互换位置,然后继续向下比较
   如果 a的值不大于b,跳出循环
 */
class niukeclass_4{
    void swap(vector<int>&arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    /*
     参数1:构成大顶堆的数组
     参数2:调整的元素的坐标
     参数3:大顶堆的元素个数
     */
    void 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, largest,index);
            index = largest;
            left = index*2 + 1;
        }
    }
};
/*
 
题目5 实现堆排序
 思路:
 1 根据数组建立大根堆
 2 每次最后一个元素和 第一个元素交换,最后一个元素就是最大值,
 然后把除了最后一个元素以外的大顶堆重新调整为大根堆
 3 直到所有元素全部调整完毕
 */
class class_heapSort {
    /*
     入口方法
     */
public:
    void heapSort(vector<int>&arr){
        if(arr.size()<2){
            return;
        }
        for (int i = 0; i < arr.size(); i++) {
            heapInsert(arr, i);
        }
        int size = (int)arr.size();
        swap(arr,0,--size);
        while (size>0) {
            heapify(arr, 0, size);//每次调整的时间复杂度为logN,效率高
            //继续交换第一个和最后一个元素
            swap(arr, 0, --size);
        }
    }
private:
    void swap(vector<int>&arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    void 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, largest,index);
            index = largest;
            left = index*2 + 1;
        }
    }
    void heapInsert(vector<int>&arr,int index){
        while (arr[index]>arr[(index-1)/2]) {
            swap(arr, index, (index-1)/2);
            index = (index-1)/2;
        }
    }
};

猜你喜欢

转载自www.cnblogs.com/xiaonanxia/p/10665279.html