zoukankan      html  css  js  c++  java
  • 快速排序/快速查找(第k个, 前k个问题)

    //快速排序:Partition分割函数,三数中值分割
    bool g_bInvalidInput = false;
    int median3(int* data, int start, int end){
        int middle = (start + end) >> 1;
        if (data[start] > data[middle])
            std::swap(data[start], data[middle]);
        if (data[start] > data[end])
            std::swap(data[start], data[end]);
        if (data[middle] > data[end])
            std::swap(data[middle], data[end]);
        std::swap(data[middle], data[end - 1]);
        return data[end - 1];
    }
    int Partition(int* data, int length, int start, int end){
        if (data == nullptr || length <=0 ||start < 0 || end > length - 1){
            g_bInvalidInput = true;
            return 0;
        }
        int pivot = median3(data, start, end);
        int i = start;
        int j = end - 1;
        for (;;){
            while (data[++i] < pivot) {;}
            while (data[--j] > pivot) {;}
            if (i < j)
                std::swap(data[i], data[j]);
            else
                break;
        }
        std::swap(data[i], data[end - 1]);
        return i;
    }
    void QuickSort(int* data, int length, int start, int end){
        if (start == end)
            return;
        int pivotIdx = Partition(data, length, start, end);
        if (pivotIdx > start){
            QuickSort(data, length, start, pivotIdx - 1);
        }
        if (pivotIdx < end){
            QuickSort(data, length, pivotIdx + 1, end);
        }
    }
    void QuickSortPort(int* data, int length){
        if (data == nullptr || length <= 0)
            return;
        QuickSort(data, length, 0, length - 1);
    }
    
    //快速排序:随机选取枢纽元, Partition分割函数
    #include <stdlib.h>
    #include <time.h>
    int randomInRange(int start, int end){
        srand((unsigned int)(time(NULL)));
        if (start == end)
            return start;
        else if (end < start)
            return end + rand() % (start - end + 1);
        else {
            return start + rand() % (end - start + 1);
        }
    }
    bool g_bInvalidInput = false;
    int Partition(int* data, int length, int start, int end){
        if (data == nullptr || length <= 0 || start < 0 || end > length - 1){
            g_bInvalidInput = true;
            return 0;
        }
        int pivotIdx = randomInRange(start, end);
        int pivot = data[pivotIdx];
        std::swap(data[pivotIdx], data[end]);
        int i = start - 1;
        int j = end;
        for (; i <= end && j >= start; ){
            while (++i <= end && data[i] < pivot) {;}
            while (--j >=start && data[j] > pivot) {;}
            if (i < j){
                std::swap(data[i], data[j]);
            }
            else
                break;
        }
        std::swap(data[i], data[end]);
        return i;
    }
    void QuickSort(int* data, int length, int start, int end){
        if (start == end)
            return;
        int pivotIdx = Partition(data, length, start, end);
        if (pivotIdx > start)
            QuickSort(data, length, start, pivotIdx - 1);
        if (pivotIdx < end)
            QuickSort(data, length, pivotIdx + 1, end);
    }
    void QuickSortPort(int* data, int length){
        if (data == nullptr || length <= 0)
            return;
        QuickSort(data, length, 0, length - 1);
    }
    
    //数组中出现次数超过一次的数字:
    // 第一种方法:转化为查找数组中位数的问题,但不一定需要排序,只要使用快速查找第k个元素即可,
    // 缺点:会修改输入数组
    #include <stdlib.h>
    #include <time.h>
    int randomInRange(int start, int end){
        srand((unsigned int)(time(NULL)));
        if (start == end)
            return start;
        else if (start > end)
            return end + rand() % (start - end + 1);
        else
            return start + rand() % (end - start + 1);
    }
    bool g_bIalidInput = false;
    int Partition(int* data, int length, int start, int end){
        if (data == nullptr || length<= 0 || start < 0 || end > length - 1){
            g_bInvalidInput = true;
            return 0;
        }
        int pivotIdx = randomInRange(start, end);
        int pivot = data[pivotIdx];
        std::swap(data[pivotIdx], data[end]);
        int i = start - 1;
        int j = end;
        while (i <= end - 1 && j >= start){
            while (data[++i] < pivot) {;}
            while (data[--j] > pivot) {;}
            if (i < j)
                std::swap(data[i], data[j]);
            else
                break;
        }
        std::swap(data[i], data[end]);
        return i;
    }
    bool CheckMoreThanHalf(int* data, int length, int result){
        bool isConfirmed = true;
        int count = 0;
        for (int i = 0; i < length; ++i){
            if (data[i] == result)
                count++;
        }
        if (count*2 <= length)
            isConfirmed = false;
        return isConfirmed;
    }
    int FindMoreThanHalf(int* data, int length){
        if (data == nullptr || length <= 0){
            g_bIalidInput = true;
            return 0;
        }
        int start = 0;
        int end = length - 1;
        int pivotIdx = Partition(data, length, start, end);
        int middle = length >> 1;
        while (pivotIdx != middle){
            if (pivotIdx < middle)
                pivotIdx = Partition(data, length, pivotIdx + 1, end);
            else
                pivotIdx = Partition(data, length, start, pivotIdx - 1);
        }
        int result = data[pivotIdx];
        if (CheckMoreThanHalf(data, length, result))
            return result;
        else {
            g_bInvalidInput = true;
            return 0;
        }
    }
    
    //数组中出现次数超过一半的数字:
    // 第二种方法:出现超过一半的数字出现总次数超过其他所有数字次数,无需修改数组
    bool g_bInvalidInput = false;
    bool CheckMoreThanHalf(int* data, int length, int result){
        bool isConfirmed = true;
        int count = 0;
        for (int i = 0; i < length; ++i){
            if (data[i] == result)
                count++;
        }
        if (count*2 <= length)
            isConfirmed = false;
        return isConfirmed;
    }
    int FindMoreThanHalf2(int* data, int length){
        if (data == nullptr || length <= 0){
            g_bInvalidInput = true;
            return 0;
        }
        int number = data[0];
        int count = 1;
        for (int i = 1; i < length; ++i){
            if (data[i] == number)
                count++;
            else if (count != 0)
                count--;
            else {
                number = data[i];
                count = 1;
            }
        }
        if (CheckMoreThanHalf(data, length, number))
            return number;
        else {
            g_bInvalidInput  = true;
            return 0;
        }
    }
    
    // 找出最小的k个数:不要求排序
    // 第一种方法:快速查找O(n)时间复杂度,利用快速排序思想,Partition函数,
    #include <stdlib.h>
    #include <time.h>
    int randomInRange(int start, int end){
        srand((unsigned int)(time(NULL)));
        if (start == end)
            return start;
        else if (start > end)
            return end + rand() % (start - end + 1);
        else
            return start + rand() % (end - start + 1);
    }
    bool g_bInvalidInput = false;
    int Partition(int* data, int length, int start, int end){
        if (data == nullptr || length<= 0 || start < 0 || end > length - 1){
            g_bInvalidInput = true;
            return 0;
        }
        int pivotIdx = randomInRange(start, end);
        int pivot = data[pivotIdx];
        std::swap(data[pivotIdx], data[end]);
        int i = start - 1;
        int j = end;
        while (i <= end - 1 && j >= start){
            while (data[++i] < pivot) {;}
            while (data[--j] > pivot) {;}
            if (i < j)
                std::swap(data[i], data[j]);
            else
                break;
        }
        std::swap(data[i], data[end]);
        return i;
    }
    void leastKNumbers(int* data, int length, int k){
        if (data == nullptr || length <= 0 || k <= 0 || k > length)
            return;
        int start = 0;
        int end = length - 1;
        int pivotIdx = Partition(data, length, start, end);
        while (pivotIdx != k - 1){
            if (pivotIdx > k - 1)
                pivotIdx = Partition(data, length, start, pivotIdx - 1);
            else
                pivotIdx = Partition(data, length, pivotIdx + 1, end);
        }
        for (int i = 0; i <= pivotIdx; ++i){
            if (i == pivotIdx)
                cout << data[i] << endl;
            else
                cout << data[i] << ' ';
    
        }
    }
    //第二种方法:利用二叉树(红黑树),STL中的set和multiset都是基于红黑树实现的最大/最小堆,支持O(log k)时间的插入c.insert(x)/删除操作c.erase(x), O(1)时间查找最大值c.begin()
    //时间复杂度:nlogk,不会修改输入数据, 不要求一次载入所有数据到内存,只要求内存存储k个数字的一个容器,一次读入一个数据;
    // 适合海量数据处理,即n很大, k很小的数据
    #include <set>
    #include <vector>
    using namespace std;
    typedef std::multiset<int, greater<int>> intSet;
    typedef std::multiset<int, greater<int>>::iterator setIterator;
    void leastKNumbers(const vector<int>& data, intSet& leastKNumbers, int k){
        leastKNumbers.clear();
        vector<int>::const_iterator iter = data.begin();
        for (; iter != data.end(); ++iter){
            if (leastKNumbers.size() < k){
                leastKNumbers.insert(*iter);
            }
            else {
                setIterator greatestIter = leastKNumbers.begin();
                if ((*iter) < (*greatestIter)){
                    leastKNumbers.erase(greatestIter);
                    leastKNumbers.insert(*iter);
                }
            }
        }
    }
    intSet leastKNumbersPort(const vector<int>& data, int k){
        if (data.size() > 0 && k > 0 && k <= data.size()){
            intSet leastKSet;
            leastKNumbers(data, leastKSet, k);
            return leastKSet;
        }
        else
            throw exception();
    }
    
  • 相关阅读:
    MySQL源代码解读(二)
    MySQL源代码解读(一)
    C语言中如何对串口进行操作
    mysql 运行概图
    Yacc 与 Lex
    外键建索引
    提高SQL查询效率
    MySQL源代码分析:(1)Main函数
    Linux "could not open default font 'fixed'."
    转帖 浅析ARM汇编语言子例程设计方法
  • 原文地址:https://www.cnblogs.com/songdanzju/p/7442015.html
Copyright © 2011-2022 走看看