# 算法笔记(0)

### [18, 4, 8, 9, 16, 1, 14, 7, 19, 3, 0, 5, 2, 11, 6];

#### 乍一看似乎不难，直接从0到最大值遍历一遍，看当前值是否已经使用，算法描述如下：

 function Min-Free(A)
x ← 0
loop
if x ∉ A then
return x
else
x ←  x + 1

#### 其中 ∉ 符号的实现如下：

 function '∉' (x, X)
for i ←1 to |X|  do
if x == X[i]  then
return False
return True

### 改进一

#### 根据这一结论，我们可以使用一个长度为n+1的数组，来标记区间[0, n]内的某个整数是否可用：

 function Min-Free(A)
F ← [False, False, ···,False] where |F| = n + 1
for ∀x ∈ A do
if x < n then
F[x] ← True
for i ← 0 to n do
if F[i] = False
return i

#### 以下为C语言实现代码

#include<stdio.h>

#define N 1000000   //100万
#define WORD_LENGTH sizeof(int) * 8

void setbit(unsigned int *bits, unsigned int i) {
bits[i / WORD_LENGTH] |= 1<<(i % WORD_LENGTH);
}

int testbit(unsigned int *bits, unsigned int i) {
return bits[i / WORD_LENGTH] & (1 << (i % WORD_LENGTH));
}

unsigned int bits[N / WORD_LENGTH + 1];

int min_free(int *xs, int n) {
int i, len =N / WORD_LENGTH +1;
for(i = 0; i < len; i++) {
bits[i] = 0;
}

for(i = 0; i < n; i++) {
if(xs[i] < n)
setbit(bits, xs[i]);
}

for(i = 0; i <= n; i++) {
if(!testbit(bits, i))
return i;
}
}

int main() {

int test[15] = {18, 4, 8, 9, 16, 1, 14, 7, 19, 3, 0, 5, 2, 11, 6};

printf("%d", min_free(test, 15));
}

#### 在上面min_free()函数中，最后一个for循环可以进一步优化，从数组第一个int开始，以int为单位（每次检查32个位）检查该int的比特位是否全为1，若不等于0xffffffff,则说明最小的可分配ID在该int范围内，再遍历该int值得32个比特位。如下：

if((!bits[i]) != 0){
for(j = 0; ; ++j)
if(!testbit(bits, i*WORD_LENGTH + j))
return i*WORD_LENGTH + j;
} 

### 改进二

#### A” = { x | ∀x∈A & x > m}

import Data.List
minFree xs = bsearch xs 0 (length xs - 1)
bsearch xs l u  | xs == [] = l
| length as == m - l + 1 = bsearch bs (m + 1) u
| otherwise = bsearch as l m
where
m = (l + u) div 2
(as, bs) = partitiopn (<= m) xs 

#### 别急，下面贴出将递归转换为迭代的C语言代码：

int min_free(int *xs, int n) {
int l = 0;
int u = n - 1;
while(n) {
int m = (l + u) / 2;
int right, left = 0;
//将小于m的值放入left左部
for(right = 0; right < n; ++ right)
if(xs[right] <= m) {
swap(xs[left], xs[right]);
++left
}

if(left == m - l + 1) {   //前半个数组满
xs = xs + left;    //寻找的下界变为 [n/2] + 1
n = n - left;
l = m + 1;
}
else {     //寻找的值在left左部
n = left;
u = m;
}
}
return l;
}


#### 前言第一个小例子完毕，还需继续加油~

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客