c++排序和红黑树

红黑树

1.节点分为红色或者黑色;
2.根节点必为黑色;
3.叶子节点都为黑色,且为null;
4.连接到】红色节点的两个子节点都为黑色(红黑树不会出现相邻的红色节点);
5.从任意节点出发,到其每个叶子节点的路径中包含相同数量的黑色节点;
6.新加入到红黑树的节点为红色节点;

引申:兄弟节点的高度不可能比当前节点大2或以上。

Case 1 当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色。 (01) 将“父节点”设为黑色。(02) 将“叔叔节点”设为黑色。 (03) 将“祖父节点”设为“红色”。 (04) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作。
Case 2 左左情况:当前节点的父节点是左孩子且为红色,叔叔节点是黑色,且当前节点是其父节点的左孩子 (01) 将“父节点”设为“黑色”。(02) 将“祖父节点”设为“红色”。 (03) 以“祖父节点”为支点进行右旋。
Case 3 左右情况:当前节点的父节点是左孩子且为红色,叔叔节点是黑色,且当前节点是其父节点的右孩子 (01) 将“父节点”作为“新的当前节点”。(02) 以“新的当前节点”为支点进行左旋(将左右情况转换成左左情况)。

插入51,首选进行变色。变色操作到祖父节点为止。如果曾祖为黑色,插入操作结束,否则以祖父为当前节点继续下一轮操作。
在这里插入图片描述
在这里插入图片描述插入65,左左旋转
在这里插入图片描述
插入67,左右旋转
在这里插入图片描述- 删除
对任何节点的删除都可以转换成对叶子节点的删除。
① 被删除节点没有儿子,即为叶节点。那么,直接将该节点删除就OK了。
② 被删除节点只有一个儿子。那么,直接删除该节点,并用该节点的唯一子节点顶替它的位置。
③ 被删除节点有两个儿子。那么,先找出它的后继节点;然后把“它的后继节点的内容”复制给“该节点的内容”;之后,删除“它的后继节点”。在这里,后继节点相当于替身,在将后继节点的内容复制给"被删除节点"之后,再将后继节点删除。这样就巧妙的将问题转换为"删除后继节点"的情况了,下面就考虑后继节点。
在这里插入图片描述在这里插入图片描述
情况4应该修正为,兄弟节点不存在红色的子节点。
删除修复的思路可以总结为,把兄弟节点所在额子树中多余的红色节点转换成黑色,并从中借一个黑色节点过来填补空缺。
递归过程可以看成当前节点所在的分支,因为以当前节点为根节点的子树中缺少了黑色节点,从而不满足5条性质。和插入不同的是,先调整再删除。

情况5应该修正为:将兄弟节点修改为黑色,父节点改为红色,然后再以父节点为支点左旋。这样可以转换成兄弟节点为黑色的情况。

快速排序

function partition(arr, left ,right) {
    
         // 分区操作
    var pivot = left,                      // 设定基准值(pivot)
        index = pivot + 1;
    for (var i = index; i <= right; i++) {
    
    
        if (arr[i] < arr[pivot]) {
    
    
            swap(arr, i, index);
            index++;
        }       
    }
    swap(arr, pivot, index - 1);
    return index-1;

index表示最左边大于等于arr[pivot]的位置
返回的index-1是排好序的位置

颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

示例 3:

输入:nums = [0]
输出:[0]

示例 4:

输入:nums = [1]
输出:[1]

提示:
n == nums.length
1 <= n <= 300
nums[i] 为 0、1 或 2

一般写法 leetcode75 60% 10%

class Solution {
    
    
public:
    void sortColors(vector<int>& nums) {
    
    
        if(nums.size()<=1){
    
    
            return;
        }else{
    
    
            sort_func(nums,0,nums.size());
            return;
        }
    }

    void sort_func(vector<int>& arr, int left, int len){
    
    
        if(len<=1){
    
    
            return;
        }else{
    
    
            int pivot=partition(arr,left,len);
            sort_func(arr,left,pivot-left);
            sort_func(arr,pivot+1,len+left-pivot-1);
        }
    }
    int partition(vector<int>& arr, int left, int len){
    
     
    // 以arr[left]为pivot_value, left 先空出来,从left+1开始循环,
    //每次循环试图找到最靠左的且值大于等于pivot_value的位置
        int pivot=-1;
        int pivot_value=arr[left];
        for(int i=left+1;i<left+len;i++){
    
    
            if(arr[i]<pivot_value && pivot>0){
    
    
                int tmp=arr[pivot];
                arr[pivot]=arr[i];
                arr[i]=tmp;
                pivot++;
            }else if(arr[i]>=pivot_value && pivot==-1){
    
    
                pivot=i;

            }
        }
        if (pivot==-1){
    
    
            pivot=left+len-1;
            arr[left]=arr[left+len-1];
            arr[left+len-1]=pivot_value;
            
        }else{
    
    
            pivot=pivot-1;
            arr[left]=arr[pivot];
            arr[pivot]=pivot_value;
        }
        return pivot;
    }
};

双指针,三区域写法

在这里插入图片描述

class Solution {
    
    
public:
    void sortColors(vector<int>& nums) {
    
    
        if(nums.size()<=1){
    
    
            return;
        }else{
    
    
            sort_func(nums,0,nums.size());
            return;
        }
    }

    void sort_func(vector<int>& arr, int left, int len){
    
    
        if(len<=1){
    
    
            return;
        }else{
    
    
            int* pivots=partition(arr,left,len);
            sort_func(arr,left,pivots[0]-left);
            sort_func(arr,pivots[1]+1,len+left-pivots[1]-1);
            delete[] pivots;
        }
    }
    int* partition(vector<int>& arr, int left, int len){
    
    
        int* p= new int[2];
        p[0]=left;
        p[1]=left+len-1;
        int cur=left;
        int pivot_value=arr[left];
        while(cur<=p[1]){
    
    
            if (arr[cur]<pivot_value){
    
    
                int tmp=arr[cur];
                arr[cur]=arr[p[0]];
                arr[p[0]]=tmp;
                p[0]++;
                cur++;
            }else if(arr[cur]>pivot_value){
    
    
                int tmp=arr[cur];
                arr[cur]=arr[p[1]];
                arr[p[1]]=tmp;
                p[1]--;
                //注意这里不需要cur++,因为p1指向的是未知区域,和cur交换之后还需要继续判断
            }else{
    
    
                cur++;
            }
        }
        return p;
    }
};

每次p[0]到p[1]是已经排好序的部分

一次遍历版本

直接把0换到最左边,2换到最右边

public:
    void sortColors(vector<int> &nums) {
    
    
        int size = nums.size();
        if (size < 2) {
    
    
            return;
        }

        // all in [0, zero) = 0
        // all in [zero, i) = 1
        // all in [two, len - 1] = 2

        int zero = 0;
        int two = size;
        int i = 0;
        while (i < two) {
    
    
            if (nums[i] == 0) {
    
    
                swap(nums[zero], nums[i]);
                zero++;
                i++;
            } else if (nums[i] == 1) {
    
    
                i++;
            } else {
    
    
                two--;
                swap(nums[i], nums[two]);
            }

topk

剑指 Offer 40. 最小的k个数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

示例 1:

输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]

示例 2:

输入:arr = [0,1,2,1], k = 1
输出:[0]

限制:

0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
class Solution {
    
    
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
    
    
        int len=arr.size();
        if(k==0){
    
    
            return vector(arr.begin(),arr.begin()+k);
        }
        sort(arr,0,len-1,k);
        return vector(arr.begin(),arr.begin()+k);

    }
    void sort(vector<int>& arr, int left, int right, int k){
    
    
        if(left==right){
    
    
            return;
        }
        int pivot=partition(arr,left,right);
        if(pivot==k-1){
    
    
                return;
        }else if(pivot>k-1){
    
    
                sort(arr,left,pivot-1,k);
        }else{
    
    
                sort(arr,pivot+1,right,k);
        }
        return;
    }
    int partition(vector<int>& arr, int left, int right){
    
    
        if(left==right){
    
    
            return left;
        }
        int tmp;
        int index=left+1;
        int value=arr[left];
        for(int i=left+1;i<=right;i++){
    
    
            if(arr[i]<value){
    
    
                tmp=arr[i];
                arr[i]=arr[index];
                arr[index]=tmp;
                index++;
            }
        }
        tmp=arr[left];
        arr[left]=arr[index-1];
        arr[index-1]=tmp;
        return index-1;
    }
};

归并排序

剑指 Offer 51. 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:

输入: [7,5,6,4]
输出: 5

限制:

0 <= 数组长度 <= 50000

class Solution {
    
    
public:
    int result;
    int reversePairs(vector<int>& nums) {
    
    
        int len=nums.size();
        if(len==0){
    
    
            return 0;
        }
        result=0;
        order(nums,0,len-1);
        return result;
    }
    void order(vector<int>& nums,int left,int right){
    
    
        vector<int> help;
        if(left==right){
    
    
            return;
        }
        
        int mid=(left+right)/2;
        order(nums,left,mid);
        order(nums,mid+1,right);
        int l=left;
        int r=mid+1;
        while(l<=mid && r<=right){
    
    
            if(nums[r]<nums[l]){
    
    
                result+=mid-l+1;
                help.push_back(nums[r]);
                r++;
            }else{
    
    
                help.push_back(nums[l]);
                l++;
            }
        }
        if(l<=mid){
    
    
            for(;l<=mid;l++){
    
    
                help.push_back(nums[l]);
            }
        }
        if(r<=right){
    
    
            for(;r<=right;r++){
    
    
                help.push_back(nums[r]);
            }
        }
        for(int i=right;i>=left;i--){
    
    
            nums[i]=help.back();
            help.pop_back();
        }
    }

};

猜你喜欢

转载自blog.csdn.net/weixin_39849839/article/details/108007553