今天是五一,晚上學C++分治算法
1、二分查找
二分查找跨度大,速度快,枚舉的跨度爲1,所以慢
二分是折半的,速度logn,非常快,基礎代碼如下
參數aTarget是目標數,aData是數列,n是數組長度
如果按照枚舉的方法,是這樣的:
bool Search(int aTarget, int aData[], int n)
{
for (int i = 0; i < n; i++)
if (aData[i] == aTarget)
return true;
return false;
}
這樣對於小範圍的數據是可以處理的
但是:如果要遍歷兩億個數呢?而且碰巧要找到的數是兩億減一的數呢?😱
於是二分查找出現了!😇
數組方法如下:
bool binarySearch(int aTarget, int aData[], int n)
{
int left = 0, right = n - 1;
while (left <= right)
{
mid = (left + right) / 2;
if (aData[mid] == aTarget)
return true;
else if (aData[mid] < aTarget)
left = mid + 1;
else
right = mid - 1;
}
return false;
}
換成動態數組更簡單了
bool binarySearch(int aTarget, vector<int> aData)
{
int left = 0, right = aData.size();
while (left <= right)
{
mid = (left + right) / 2;
if (aData[mid] == aTarget)
return true;
else if (aData[mid] < aTarget)
left = mid + 1;
else
right = mid - 1;
}
return false;
}
最簡單的還是algorithm庫中的函數,直接給圖
1、1二分查找練習題-砍樹
這個題目用枚舉顯然不行,於是二分查找又偉大的出現了!
其實很簡單
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
int main()
{
vector<int>trees;
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
int tmp;
cin >> tmp;
trees.push_back(tmp);
}
sort(trees.begin(), trees.end());
//inend
printf("trees[trees.size() - 1] = %d\n", trees[trees.size() - 1]);
int left = 1, right = trees[trees.size() - 1];
int ans;
printf("----\n");
while (left <= right)
{
int all = 0;
int mid = (left + right) / 2;
printf("left = %d, right = %d, mid = %d\n", left, right, mid);
for (int i = 0; i < trees.size(); i++)
if (trees[i] - mid < 0)
all += 0;
else
all += trees[i] - mid;
cout << "all:" << all << endl;
if (all < m)
left = mid + 1;
else
right = mid - 1;
ans = all;
}
cout << ans << endl;
return 0;
}
2、快速排序
這是一個經典的分治,我有一個動圖來演示!
它的基本原理是基準數
給一個快速排序的地址:https://www.jianshu.com/p/497b8ee8b517
整個排序算法專欄:https://www.jianshu.com/c/0b8a16f39eab
歸併排序也是基於分治的思想,不過歸併流程是將子集合合併成爲有序的集合,遞歸執行來完成整個集合的排序。快速排序的分治流程是根據選定元素,將集合分隔爲兩個子集合,一個子集合中所有元素不大於選定元素值,另一個子集合中所有元素不小於選定元素值,則用於拆分集合的選定元素即爲已排序元素。即每次拆分都會形成一個已排序元素,所以 個元素的序列,拆分的次數級別爲O(N)。將拆分過程類比爲二叉樹形式,考慮普通二叉樹和斜樹的情況,則二叉樹高度級別爲O(log2N)~O(N)。
作者:zhipingChen
鏈接:https://www.jianshu.com/p/497b8ee8b517
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
實現!
迭代法
typedef struct _Range {
int start, end;
} Range;
Range new_Range(int s, int e) {
Range r;
r.start = s;
r.end = e;
return r;
}
void swap(int *x, int *y) {
int t = *x;
*x = *y;
*y = t;
}
void quick_sort(int arr[], const int len) {
if (len <= 0)
return; // 避免len等於負值時引發段錯誤(Segment Fault)
// r[]模擬列表,p為數量,r[p++]為push,r[--p]為pop且取得元素
Range r[len];
int p = 0;
r[p++] = new_Range(0, len - 1);
while (p) {
Range range = r[--p];
if (range.start >= range.end)
continue;
int mid = arr[(range.start + range.end) / 2]; // 選取中間點為基準點
int left = range.start, right = range.end;
do
{
while (arr[left] < mid) ++left; // 檢測基準點左側是否符合要求
while (arr[right] > mid) --right; //檢測基準點右側是否符合要求
if (left <= right)
{
swap(&arr[left],&arr[right]);
left++;right--; // 移動指針以繼續
}
} while (left <= right);
if (range.start < right) r[p++] = new_Range(range.start, right);
if (range.end > left) r[p++] = new_Range(left, range.end);
}
}
遞歸法
void swap(int *x, int *y) {
int t = *x;
*x = *y;
*y = t;
}
void quick_sort_recursive(int arr[], int start, int end) {
if (start >= end)
return;
int mid = arr[end];
int left = start, right = end - 1;
while (left < right) {
while (arr[left] < mid && left < right)
left++;
while (arr[right] >= mid && left < right)
right--;
swap(&arr[left], &arr[right]);
}
if (arr[left] >= arr[end])
swap(&arr[left], &arr[end]);
else
left++;
if (left)
quick_sort_recursive(arr, start, left - 1);
quick_sort_recursive(arr, left + 1, end);
}
void quick_sort(int arr[], int len) {
quick_sort_recursive(arr, 0, len - 1);
}