集合運算(整數區間) C實現
阿新 • • 發佈:2020-12-13
技術標籤:C
整數區間的集合運算
摘要
最近寫專案程式碼裡用到很多整數區間運算,呼叫頻率很高,想著網上有沒有好的封裝借鑑一下。奈何一頓搜尋猛如虎,合用封裝基本無。不如自己寫一個了。
- 交集:先用 overlap() 判斷一些區間是否有重疊,然後求出重疊部分即可;
- 差集:先求交集,然後再減去交集。
話不多說,直接上程式碼,備註完善,測試可用。
程式碼
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#define LEFT(p) (p[0])
#define RIGHT(p) (p[1])
int max(int x, int y) {
return x > y ? x : y;
}
int min(int x, int y) {
return x > y ? y : x;
}
/**
* @brief 判斷兩個整數區間是否重疊
* @param x 區間: [x[0], x[1]]
* @param y 區間: [y[0], y[1]]
* @return true 重疊; false 不重疊
*/
bool overlap(const int* x, const int* y) {
if (!x || !y) return false;
int begin = max(LEFT(x), LEFT(y));
int end = min(RIGHT(x), RIGHT(y));
return end - begin >= 0;
}
/**
* @brief 交集(整數區間)
* @param x 區間: [x[0], x[1]]
* @param y 區間: [y[0], y[1]]
* @param is 所求交集
* @return true 有交集; false 無交集
*/
bool intersection(const int* x, const int* y, int * is) {
if (overlap(x, y)) {
LEFT(is) = max(LEFT(x), LEFT(y));
RIGHT(is) = min(RIGHT(x), RIGHT(y));
return true;
}
return false;
}
/**
* @brief 差集(整數區間): 屬於x但不屬於y 區間合法性由呼叫者保證
* @param x 區間: [x[0], x[1]]
* @param y 區間: [y[0], y[1]]
* @param ds 差集區間
* @param n 返回的差集數量
*/
void differenceSet(const int* x, const int* y, int ds[][2], int* n) {
int is[2];
int c = 0;
if (intersection(x, y, is)) {
if (LEFT(is) > LEFT(x)) {
LEFT(ds[c]) = LEFT(x);
RIGHT(ds[c]) = LEFT(is) - 1;
c++;
}
if (RIGHT(is) < RIGHT(x)) {
LEFT(ds[c]) = RIGHT(is) + 1;
RIGHT(ds[c]) = RIGHT(x);
c++;
}
} else {
LEFT(ds[c]) = LEFT(x);
RIGHT(ds[c]) = RIGHT(x);
c = 1;
}
*n = c;
}
/**
* @brief 集合運算(整數區間)
* 區間有效性由呼叫者保證: 有效區間 x 滿足 LEFT(x) <= RIGHT(x)
*/
int main() {
int x[2];
int y[2];
int is[2]; // 存放所求得的交集
int ds[2][2]; // 存放所求得的差集
int n; // 差集數量,0 ~ 2
printf("請輸入整數區間x: ");
scanf("%d %d", &LEFT(x), &RIGHT(x));
assert(LEFT(x) <= RIGHT(x));
printf("請輸入整數區間y: ");
scanf("%d %d", &LEFT(y), &RIGHT(y));
assert(LEFT(y) <= RIGHT(y));
// 交集
intersection(x, y, is) ?
printf("交集: [%d %d]\n", LEFT(is), RIGHT(is)) :
printf("不相交\n");
// 差集
differenceSet(x, y, ds, &n);
switch (n) {
case 0:
printf("差集為空(區間 y 包含區間 x)\n");
break;
case 1:
printf("差集: [%d %d]\n", LEFT(ds[0]), RIGHT(ds[0]));
break;
case 2:
printf("差集: [%d %d] + [%d %d]\n", LEFT(ds[0]), RIGHT(ds[0]), LEFT(ds[1]), RIGHT(ds[1]));
break;
default:
break;
}
}
測試
# 生成測試檔案 a.out
gcc interval.c
$ ./a.out
請輸入整數區間x: 5 9
請輸入整數區間y: 1 4
不相交
差集: [5 9]
$ ./a.out
請輸入整數區間x: 5 9
請輸入整數區間y: 10 19
不相交
差集: [5 9]
$ ./a.out
請輸入整數區間x: 5 9
請輸入整數區間y: 5 9
交集: [5 9]
差集為空(區間 y 包含區間 x)
$ ./a.out
請輸入整數區間x: 5 9
請輸入整數區間y: 5 6
交集: [5 6]
差集: [7 9]
$ ./a.out
請輸入整數區間x: 5 9
請輸入整數區間y: 6 9
交集: [6 9]
差集: [5 5]
$ ./a.out
請輸入整數區間x: 5 9
請輸入整數區間y: 4 10
交集: [5 9]
差集為空(區間 y 包含區間 x)
$ ./a.out
請輸入整數區間x: 5 9
請輸入整數區間y: 4 8
交集: [5 8]
差集: [9 9]
$ ./a.out
請輸入整數區間x: 5 9
請輸入整數區間y: 6 560
交集: [6 9]
差集: [5 5]