天天看点

分治策略

二分查找

循环二分查找

int BinaryFindValue(const int* ar, int n, int val)//循环的二分查询
{
    assert(ar != NULL); // NULL  nullptr;
    int pos = -1;
    int left = 0, right = n - 1;
    while (left <= right) // left < right
    {
        //int mid = (right + left) / 2;//可能左右相加超出整形数组的范围,
        int mid = (right - left) / 2 + left;//
        if (val < ar[mid]) 
        {
            right = mid - 1;
        }
        else if (val > ar[mid])
        {
            left = mid + 1;
        }
        else
        {
            while (mid > left && ar[mid - 1] == val)
            {
                mid = mid - 1;
            }
            pos = mid;
            break;
        }
    }
    return pos;
}
int main()
{
    int ar[] = { 12,23,34,45,56,67,78,89,90,100 };
    int n = sizeof(ar) / sizeof(ar[0]);
    int val;
    cin >> val;
    int pos = BinaryFindValue(ar, n, val);//二分查询
    cout << pos << endl;

    return 0;
}      

递归二分查找

int FindValue(const int* ar, int left, int right, int val)
{
    int pos = -1;
    if (left <= right)
    {
        int mid = (right - left) / 2 + left;
        if (val < ar[mid])
        {
            pos = FindValue(ar, left, mid - 1, val);
        }
        else if (val > ar[mid])
        {
            pos = FindValue(ar, mid + 1, right, val);
        }
        else
        {
            pos = mid;
        }
    }
    return pos;
}
//递归的二分查询
int BinFindValue(const int* ar, int n, int val)
{
    assert(ar != nullptr);
    return FindValue(ar, 0, n - 1, val);
}

int main()
{
    int ar[] = { 12,23,34,45,56,67,78,89,90,100 };
    int n = sizeof(ar) / sizeof(ar[0]);
    int val;
    cin >> val;
    pos = BinFindValue(ar, n, val);//递归的二分查询
    cout << pos << endl;

    return 0;
}      

快速排序法

递归

void Print_Ar(int* ar, int n)
{
    for (int i = 0; i < n; ++i)
    {
        printf("%4d ", ar[i]);
    }
    printf("\n");
}
int Parition(int* ar, int left, int right)
{
    int tmp = ar[left];
    while (left < right)
    {
        while (left < right && tmp < ar[right]) --right;
        if (left < right) ar[left] = ar[right];
        while (left < right && ar[left] <= tmp) ++left;
        if (left < right) ar[right] = ar[left];
    }
    ar[left] = tmp;
    return left;
}
void QuickPass(int* ar, int left, int right)//快速排序
{
    if (left < right)
    {
        int pos = OneParition(ar, left, right);
        QuickPass(ar, left, pos - 1);
        QuickPass(ar, pos + 1, right);
    }
}
void QuickSort(int* ar, int n)//快排
{
    assert(ar != NULL);
    QuickPass(ar, 0, n - 1);
}
int main()
{
    int ar[] = { 56,23,34,89,90,12,78,45,56,100,67 };
    int n = sizeof(ar) / sizeof(ar[0]);

    Print_Ar(ar, n);
    QuickSort(ar, n);
    Print_Ar(ar, n);
    return 0;
}      

栈、

void NiceQuickSort(int* ar, int n)
{
    assert(ar != nullptr);
    stack<int> ist;
    ist.push(0);
    ist.push(n - 1);
    while (!ist.empty())
    {
        int right = ist.top(); ist.pop();
        int left = ist.top(); ist.pop();
        int pos = Parition(ar, left, right);

        if (left < pos - 1)
        {
            ist.push(left);
            ist.push(pos - 1);
        }
        if (pos + 1 < right)
        {
            ist.push(pos + 1);
            ist.push(right);
        }
    }
}      

队列

void NiceQuickSort(int* ar, int n)
{
    assert(ar != nullptr);
    queue<int>  ist;
    ist.push(0);
    ist.push(n - 1);
    while (!ist.empty())
    {
        int left = ist.front(); ist.pop();
        int right = ist.front(); ist.pop();

        int pos = Parition(ar, left, right);

        if (left < pos - 1)
        {
            ist.push(left);
            ist.push(pos - 1);
        }
        if (pos + 1 < right)
        {
            ist.push(pos + 1);
            ist.push(right);
        }
    }
}      

队的另一种方法:

void NiceQuickSort(int* ar, int n)
{
    assert(ar != nullptr);
    queue<std::pair<int, int> > ist;//pair 一对  有first,second

    std::pair<int, int> LR(0, n - 1);
    ist.push(LR);
    while (!ist.empty())
    {
        std::pair<int, int> LR = ist.front(); ist.pop();

        int pos = RandParition(ar, LR.first, LR.second);

        if (LR.first < pos - 1)
        {
            ist.push(pair<int, int>(LR.first, pos - 1));
        }
        if (pos + 1 < LR.second)
        {
            ist.push(pair<int, int>(pos + 1, LR.second));
        }
    }
}      

若数据本来有序,(若从第一个开始划分,变成冒泡排序)

使用随机法

int Parition(int* ar, int left, int right)
{
    int tmp = ar[left];
    while (left < right)
    {
        while (left < right && tmp < ar[right]) --right;
        if (left < right) ar[left] = ar[right];
        while (left < right && ar[left] <= tmp) ++left;
        if (left < right) ar[right] = ar[left];
    }
    ar[left] = tmp;
    return left;
}
int RandParition(int* ar, int left, int right)
{
    assert(ar != nullptr);
    int index = rand() % (right - left + 1) + left;
    //模值加left,模值得到的是第几位,而不是物理下标,加left得到那一位的物理下标
    std::swap(ar[index], ar[left]);
    return Parition(ar, left, right);
}      

适合单链表的:冒泡,选择

int OneParition(int* ar, int left, int right)
{
    int i = left, j = left - 1;
    int tmp = ar[i];
    while (i <= right)
    {
        if (ar[i] <= tmp)
        {
            j = j + 1;
            std::swap(ar[i], ar[j]);
        }
        ++i;
    }
    std::swap(ar[left], ar[j]);
    return j;
}      

单链表的快排

含头结点的快排:

typedef int ElemType;
typedef struct ListNode
{
    ElemType data;
    struct ListNode* next;
}ListNode, * LinkList;

struct ListNode* Buynode()
{
    struct ListNode* s = (struct ListNode*)malloc(sizeof(struct ListNode));
    if (NULL == s) exit(1);
    memset(s, 0, sizeof(struct ListNode));
    return s;
}
struct ListNode* InitList()
{
    struct ListNode* s = Buynode();
    return s;
}
void Push_Front(LinkList phead, ElemType val)
{
    ListNode* s = Buynode();
    s->data = val;
    s->next = phead->next;
    phead->next = s;
}
void PrintList(LinkList phead)
{
    ListNode* p = phead->next;
    while (p != nullptr)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}
ListNode* Parition(ListNode* first, ListNode* end)
{
    ListNode* jp = first;
    ListNode* ip = first->next;//ip指向第一个数据的结点
    int tmp = ip->data;
    while (ip != end)
    {
        if (ip->data <= tmp)
        {
            jp = jp->next;
            std::swap(jp->data, ip->data);//交换函数
        }
        ip = ip->next;
    }
    std::swap(first->data, jp->data);//退出后第一个与jp指向的交换
    return jp;
}

void QuickPass(ListNode* first, ListNode* end)
{
    if (first != end)//first指第一个结点,end指向的是空
    { 
        ListNode* pos = Parition(first, end);
        QuickPass(first, pos);
        QuickPass(pos, end);
    }
}
void QuickSort(ListNode head)
{
    assert(head != nullptr);
    QuickPass(head, NULL);
}
int main()
{
    int ar[] = { 56,23,34,89,90,12,78,45,100,67 };
    int n = sizeof(ar) / sizeof(ar[0]);
    LinkList head = InitList();
    for (int i = n - 1; i >= 0; --i)
    {
       Push_Front(head, ar[i]);
    }

    PrintList(head);
    QuickSort(head);
    PrintList(head);
    return 0;
}      

不含头结点的快排:

typedef int ElemType;
typedef struct ListNode
{
    ElemType data;
    struct ListNode* next;
}ListNode, * LinkList;

struct ListNode* Buynode()
{
    struct ListNode* s = (struct ListNode*)malloc(sizeof(struct ListNode));
    if (NULL == s) exit(1);
    memset(s, 0, sizeof(struct ListNode));
    return s;
}
struct ListNode* InitList()
{
    struct ListNode* s = Buynode();
    return s;
}
ListNode* Push_Front(LinkList phead, ElemType val)
{
    if (phead == nullptr)
    {
        ListNode* s = Buynode();
        s->data = val;
        s->next = nullptr;
        return s;
    }
    ListNode* s = Buynode();
    s->data = val;
    s->next = phead;
    phead = s;
    return phead;
}
void PrintList(LinkList phead)
{
    ListNode* p = phead;
    while (p != nullptr)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}
ListNode* Parition(ListNode* first, ListNode* end)
{
    ListNode* jp = first;
    ListNode* ip = first->next;//ip指向第一个数据的结点
    int tmp = jp->data;
    while (ip != end)
    {
        if (ip->data <= tmp)
        {
            jp = jp->next;
            std::swap(jp->data, ip->data);//交换函数
        }
        ip = ip->next;
    }
    std::swap(first->data, jp->data);//退出后第一个与jp指向的交换
    return jp;
}

void QuickPass(ListNode* first, ListNode* end)
{
    if (first != end)//first指第一个结点,end指向的是空
    { 
        ListNode* pos = Parition(first, end);
        QuickPass(first, pos);
        QuickPass(pos->next, end);
    }
}
void QuickSort(ListNode* phead)
{
    assert(phead != nullptr);
    QuickPass(phead, NULL);
}
int main()
{
    int ar[] = { 56,23,34,89,90,12,78,45,100,67 };
    int n = sizeof(ar) / sizeof(ar[0]);
    LinkList head = nullptr;
    for (int i = n - 1; i >= 0; --i)
    {
        head = Push_Front(head, ar[i]);
    }

    PrintList(head);
    QuickSort(head);
    PrintList(head);
    return 0;
}      

寻找第k小的值:

int Parition(int* ar, int left, int right)
{
    int tmp = ar[left];
    while (left < right)
    {
        while (left < right && tmp < ar[right]) --right;
        if (left < right) ar[left] = ar[right];
        while (left < right && ar[left] <= tmp) ++left;
        if (left < right) ar[right] = ar[left];
    }
    ar[left] = tmp;
    return left;
}
int SelectK(int* ar, int left, int right, int k)
{
    if (left == right && k == 1) return ar[left];//此时下标只有一个值
    int pos = Parition(ar, left, right);
    int j = pos - left + 1;
    if (k <= j) return SelectK(ar, left, pos, k);
    else return SelectK(ar, pos + 1, right, k - j);
}
int Select_K_Min(int* ar, int n, int k)//找第k小
{
    assert(ar != NULL && k >= 1 && k <= n);
    return SelectK(ar, 0, n - 1, k);
}
int main()
{
    int ar[] = { 56,23,34,89,90,12,78,45,100,67 };
    int n = sizeof(ar) / sizeof(ar[0]);

    for (int k = 1; k <= n; ++k)
    {
        printf("%d => %d \n", k, Select_K_Min(ar, n, k));
    }

    return 0;

}               

 分治算法

int Parition(int* ar, int left, int right)
{
    int tmp = ar[left];
    while (left < right)
    {
        while (left < right && tmp < ar[right]) --right;
        if (left < right) ar[left] = ar[right];
        while (left < right && ar[left] <= tmp) ++left;
        if (left < right) ar[right] = ar[left];
    }
    ar[left] = tmp;
    return left;
}
int SelectK(int* ar, int left, int right, int k)
{
    if (left == right && k == 1) return ar[left];//此时下标只有一个值
    int pos = Parition(ar, left, right);
    int j = pos - left + 1;//pos-left指物理下标,实第几小时应加1
    if (k <= j) return SelectK(ar, left, pos, k);
    else return SelectK(ar, pos + 1, right, k - j);
}
int Select_K_Min(int* ar, int n, int k)//找第k小
{
    assert(ar != NULL && k >= 1 && k <= n);
    return SelectK(ar, 0, n - 1, k);
}

int MaxS1(int* ar, int left, int right)
{
    return ar[right];
}
int MinS2(int* ar, int left, int right)//物理区域找最小值
{
    int min = ar[left];
    for (int i = left + 1; i <= right; ++i)
    {
        if (min > ar[i])
        {
            min = ar[i];
        }
    }
    return min;
}
int Min(int a, int b)
{
    return a < b ? a : b;
}
int Min3(int a, int b, int c)//三个数比较最小值
{
    return Min(Min(a, b), c);
}
int Capir(int* ar, int left, int right)
{if (right - left <= 1) 
    {
        return INT_MAX;
    }
    int k = (right - left + 1) / 2;
    SelectK(ar, left, right, k);
    int pos = k + left - 1;//物理下标


    //此时是物理下标
    int d1 = Capir(ar, left, pos);     //s1;
    int d2 = Capir(ar, pos + 1, right); //s2;
    int p = MaxS1(ar, left, pos); //s1;
    int q = MinS2(ar, pos + 1, right);return Min3(d1, d2, d3);
}
int main()
{
    int ar[] = { 56,23,34,89,92,12,78,45,100,67,55 };
    int n = sizeof(ar) / sizeof(ar[0]);

    int dist= Capir(ar, 0, n - 1);
    printf("%d \n",dist);
    return 0;
}