gravatar
deba@inf.elte.hu
deba@inf.elte.hu
Bug fix in heap unionfind (ticket #197) The minimum item in the unionfind tree might become inconsistent when the split operation merges two subtrees which have equal keys. The current changeset fix the problem. It also fix a wrong index.
0 1 0
default
1 file changed with 28 insertions and 12 deletions:
↑ Collapse diff ↑
Ignore white space 128 line context
... ...
@@ -1116,184 +1116,186 @@
1116 1116
      nodes[id].right = nodes[jd].prev;
1117 1117
    }
1118 1118

	
1119 1119
    void splice(int id, int jd) {
1120 1120
      nodes[id].size += nodes[jd].size;
1121 1121
      nodes[nodes[id].right].next = nodes[jd].left;
1122 1122
      nodes[nodes[jd].left].prev = nodes[id].right;
1123 1123
      int kd = nodes[jd].left;
1124 1124
      while (kd != -1) {
1125 1125
        nodes[kd].parent = id;
1126 1126
        kd = nodes[kd].next;
1127 1127
      }
1128 1128
      nodes[id].right = nodes[jd].right;
1129 1129
    }
1130 1130

	
1131 1131
    void split(int id, int jd) {
1132 1132
      int kd = nodes[id].parent;
1133 1133
      nodes[kd].right = nodes[id].prev;
1134 1134
      nodes[nodes[id].prev].next = -1;
1135 1135

	
1136 1136
      nodes[jd].left = id;
1137 1137
      nodes[id].prev = -1;
1138 1138
      int num = 0;
1139 1139
      while (id != -1) {
1140 1140
        nodes[id].parent = jd;
1141 1141
        nodes[jd].right = id;
1142 1142
        id = nodes[id].next;
1143 1143
        ++num;
1144 1144
      }
1145 1145
      nodes[kd].size -= num;
1146 1146
      nodes[jd].size = num;
1147 1147
    }
1148 1148

	
1149 1149
    void pushLeft(int id, int jd) {
1150 1150
      nodes[id].size += 1;
1151 1151
      nodes[jd].next = nodes[id].left;
1152 1152
      nodes[jd].prev = -1;
1153 1153
      nodes[nodes[id].left].prev = jd;
1154 1154
      nodes[id].left = jd;
1155 1155
      nodes[jd].parent = id;
1156 1156
    }
1157 1157

	
1158 1158
    void popLeft(int id) {
1159 1159
      nodes[id].size -= 1;
1160 1160
      int jd = nodes[id].left;
1161 1161
      nodes[nodes[jd].next].prev = -1;
1162 1162
      nodes[id].left = nodes[jd].next;
1163 1163
    }
1164 1164

	
1165 1165
    void repairLeft(int id) {
1166 1166
      int jd = ~(classes[id].parent);
1167 1167
      while (nodes[jd].left != -1) {
1168 1168
        int kd = nodes[jd].left;
1169 1169
        if (nodes[jd].size == 1) {
1170 1170
          if (nodes[jd].parent < 0) {
1171 1171
            classes[id].parent = ~kd;
1172 1172
            classes[id].depth -= 1;
1173 1173
            nodes[kd].parent = ~id;
1174 1174
            deleteNode(jd);
1175 1175
            jd = kd;
1176 1176
          } else {
1177 1177
            int pd = nodes[jd].parent;
1178 1178
            if (nodes[nodes[jd].next].size < cmax) {
1179 1179
              pushLeft(nodes[jd].next, nodes[jd].left);
1180
              if (less(nodes[jd].left, nodes[jd].next)) {
1181
                nodes[nodes[jd].next].prio = nodes[nodes[jd].left].prio;
1182
                nodes[nodes[jd].next].item = nodes[nodes[jd].left].item;
1180
              if (nodes[jd].item == nodes[pd].item) {
1181
                nodes[nodes[jd].next].prio = nodes[jd].prio;
1182
                nodes[nodes[jd].next].item = nodes[jd].item;
1183 1183
              }
1184 1184
              popLeft(pd);
1185 1185
              deleteNode(jd);
1186 1186
              jd = pd;
1187 1187
            } else {
1188 1188
              int ld = nodes[nodes[jd].next].left;
1189 1189
              popLeft(nodes[jd].next);
1190 1190
              pushRight(jd, ld);
1191
              if (less(ld, nodes[jd].left)) {
1191
              if (less(ld, nodes[jd].left) || 
1192
                  nodes[ld].item == nodes[pd].item) {
1192 1193
                nodes[jd].item = nodes[ld].item;
1193
                nodes[jd].prio = nodes[jd].prio;
1194
                nodes[jd].prio = nodes[ld].prio;
1194 1195
              }
1195 1196
              if (nodes[nodes[jd].next].item == nodes[ld].item) {
1196 1197
                setPrio(nodes[jd].next);
1197 1198
              }
1198 1199
              jd = nodes[jd].left;
1199 1200
            }
1200 1201
          }
1201 1202
        } else {
1202 1203
          jd = nodes[jd].left;
1203 1204
        }
1204 1205
      }
1205 1206
    }
1206 1207

	
1207 1208
    void repairRight(int id) {
1208 1209
      int jd = ~(classes[id].parent);
1209 1210
      while (nodes[jd].right != -1) {
1210 1211
        int kd = nodes[jd].right;
1211 1212
        if (nodes[jd].size == 1) {
1212 1213
          if (nodes[jd].parent < 0) {
1213 1214
            classes[id].parent = ~kd;
1214 1215
            classes[id].depth -= 1;
1215 1216
            nodes[kd].parent = ~id;
1216 1217
            deleteNode(jd);
1217 1218
            jd = kd;
1218 1219
          } else {
1219 1220
            int pd = nodes[jd].parent;
1220 1221
            if (nodes[nodes[jd].prev].size < cmax) {
1221 1222
              pushRight(nodes[jd].prev, nodes[jd].right);
1222
              if (less(nodes[jd].right, nodes[jd].prev)) {
1223
                nodes[nodes[jd].prev].prio = nodes[nodes[jd].right].prio;
1224
                nodes[nodes[jd].prev].item = nodes[nodes[jd].right].item;
1223
              if (nodes[jd].item == nodes[pd].item) {
1224
                nodes[nodes[jd].prev].prio = nodes[jd].prio;
1225
                nodes[nodes[jd].prev].item = nodes[jd].item;
1225 1226
              }
1226 1227
              popRight(pd);
1227 1228
              deleteNode(jd);
1228 1229
              jd = pd;
1229 1230
            } else {
1230 1231
              int ld = nodes[nodes[jd].prev].right;
1231 1232
              popRight(nodes[jd].prev);
1232 1233
              pushLeft(jd, ld);
1233
              if (less(ld, nodes[jd].right)) {
1234
              if (less(ld, nodes[jd].right) ||
1235
                  nodes[ld].item == nodes[pd].item) {
1234 1236
                nodes[jd].item = nodes[ld].item;
1235
                nodes[jd].prio = nodes[jd].prio;
1237
                nodes[jd].prio = nodes[ld].prio;
1236 1238
              }
1237 1239
              if (nodes[nodes[jd].prev].item == nodes[ld].item) {
1238 1240
                setPrio(nodes[jd].prev);
1239 1241
              }
1240 1242
              jd = nodes[jd].right;
1241 1243
            }
1242 1244
          }
1243 1245
        } else {
1244 1246
          jd = nodes[jd].right;
1245 1247
        }
1246 1248
      }
1247 1249
    }
1248 1250

	
1249 1251

	
1250 1252
    bool less(int id, int jd) const {
1251 1253
      return comp(nodes[id].prio, nodes[jd].prio);
1252 1254
    }
1253 1255

	
1254 1256
    bool equal(int id, int jd) const {
1255 1257
      return !less(id, jd) && !less(jd, id);
1256 1258
    }
1257 1259

	
1258 1260

	
1259 1261
  public:
1260 1262

	
1261 1263
    /// \brief Returns true when the given class is alive.
1262 1264
    ///
1263 1265
    /// Returns true when the given class is alive, ie. the class is
1264 1266
    /// not nested into other class.
1265 1267
    bool alive(int cls) const {
1266 1268
      return classes[cls].parent < 0;
1267 1269
    }
1268 1270

	
1269 1271
    /// \brief Returns true when the given class is trivial.
1270 1272
    ///
1271 1273
    /// Returns true when the given class is trivial, ie. the class
1272 1274
    /// contains just one item directly.
1273 1275
    bool trivial(int cls) const {
1274 1276
      return classes[cls].left == -1;
1275 1277
    }
1276 1278

	
1277 1279
    /// \brief Constructs the union-find.
1278 1280
    ///
1279 1281
    /// Constructs the union-find.
1280 1282
    /// \brief _index The index map of the union-find. The data
1281 1283
    /// structure uses internally for store references.
1282 1284
    HeapUnionFind(ItemIntMap& _index)
1283 1285
      : index(_index), first_class(-1),
1284 1286
        first_free_class(-1), first_free_node(-1) {}
1285 1287

	
1286 1288
    /// \brief Insert a new node into a new component.
1287 1289
    ///
1288 1290
    /// Insert a new node into a new component.
1289 1291
    /// \param item The item of the new node.
1290 1292
    /// \param prio The priority of the new node.
1291 1293
    /// \return The class id of the one-item-heap.
1292 1294
    int insert(const Item& item, const Value& prio) {
1293 1295
      int id = newNode();
1294 1296
      nodes[id].item = item;
1295 1297
      nodes[id].prio = prio;
1296 1298
      nodes[id].size = 0;
1297 1299

	
1298 1300
      nodes[id].prev = -1;
1299 1301
      nodes[id].next = -1;
... ...
@@ -1339,169 +1341,183 @@
1339 1341
    /// an STL range which should be contains valid class ids. The
1340 1342
    /// time complexity is O(log(n)*k) where n is the overall number
1341 1343
    /// of the joined nodes and k is the number of classes.
1342 1344
    /// \return The class of the joined classes.
1343 1345
    /// \pre The range should contain at least two class ids.
1344 1346
    template <typename Iterator>
1345 1347
    int join(Iterator begin, Iterator end) {
1346 1348
      std::vector<int> cs;
1347 1349
      for (Iterator it = begin; it != end; ++it) {
1348 1350
        cs.push_back(*it);
1349 1351
      }
1350 1352

	
1351 1353
      int class_id = newClass();
1352 1354
      { // creation union-find
1353 1355

	
1354 1356
        if (first_class != -1) {
1355 1357
          classes[first_class].prev = class_id;
1356 1358
        }
1357 1359
        classes[class_id].next = first_class;
1358 1360
        classes[class_id].prev = -1;
1359 1361
        first_class = class_id;
1360 1362

	
1361 1363
        classes[class_id].depth = classes[cs[0]].depth;
1362 1364
        classes[class_id].parent = classes[cs[0]].parent;
1363 1365
        nodes[~(classes[class_id].parent)].parent = ~class_id;
1364 1366

	
1365 1367
        int l = cs[0];
1366 1368

	
1367 1369
        classes[class_id].left = l;
1368 1370
        classes[class_id].right = l;
1369 1371

	
1370 1372
        if (classes[l].next != -1) {
1371 1373
          classes[classes[l].next].prev = classes[l].prev;
1372 1374
        }
1373 1375
        classes[classes[l].prev].next = classes[l].next;
1374 1376

	
1375 1377
        classes[l].prev = -1;
1376 1378
        classes[l].next = -1;
1377 1379

	
1378 1380
        classes[l].depth = leftNode(l);
1379 1381
        classes[l].parent = class_id;
1380 1382

	
1381 1383
      }
1382 1384

	
1383 1385
      { // merging of heap
1384 1386
        int l = class_id;
1385 1387
        for (int ci = 1; ci < int(cs.size()); ++ci) {
1386 1388
          int r = cs[ci];
1387 1389
          int rln = leftNode(r);
1388 1390
          if (classes[l].depth > classes[r].depth) {
1389 1391
            int id = ~(classes[l].parent);
1390 1392
            for (int i = classes[r].depth + 1; i < classes[l].depth; ++i) {
1391 1393
              id = nodes[id].right;
1392 1394
            }
1393 1395
            while (id >= 0 && nodes[id].size == cmax) {
1394 1396
              int new_id = newNode();
1395 1397
              int right_id = nodes[id].right;
1396 1398

	
1397 1399
              popRight(id);
1398 1400
              if (nodes[id].item == nodes[right_id].item) {
1399 1401
                setPrio(id);
1400 1402
              }
1401 1403
              push(new_id, right_id);
1402 1404
              pushRight(new_id, ~(classes[r].parent));
1403
              setPrio(new_id);
1405

	
1406
              if (less(~classes[r].parent, right_id)) {
1407
                nodes[new_id].item = nodes[~classes[r].parent].item;
1408
                nodes[new_id].prio = nodes[~classes[r].parent].prio;
1409
              } else {
1410
                nodes[new_id].item = nodes[right_id].item;
1411
                nodes[new_id].prio = nodes[right_id].prio;
1412
              }
1404 1413

	
1405 1414
              id = nodes[id].parent;
1406 1415
              classes[r].parent = ~new_id;
1407 1416
            }
1408 1417
            if (id < 0) {
1409 1418
              int new_parent = newNode();
1410 1419
              nodes[new_parent].next = -1;
1411 1420
              nodes[new_parent].prev = -1;
1412 1421
              nodes[new_parent].parent = ~l;
1413 1422

	
1414 1423
              push(new_parent, ~(classes[l].parent));
1415 1424
              pushRight(new_parent, ~(classes[r].parent));
1416 1425
              setPrio(new_parent);
1417 1426

	
1418 1427
              classes[l].parent = ~new_parent;
1419 1428
              classes[l].depth += 1;
1420 1429
            } else {
1421 1430
              pushRight(id, ~(classes[r].parent));
1422 1431
              while (id >= 0 && less(~(classes[r].parent), id)) {
1423 1432
                nodes[id].prio = nodes[~(classes[r].parent)].prio;
1424 1433
                nodes[id].item = nodes[~(classes[r].parent)].item;
1425 1434
                id = nodes[id].parent;
1426 1435
              }
1427 1436
            }
1428 1437
          } else if (classes[r].depth > classes[l].depth) {
1429 1438
            int id = ~(classes[r].parent);
1430 1439
            for (int i = classes[l].depth + 1; i < classes[r].depth; ++i) {
1431 1440
              id = nodes[id].left;
1432 1441
            }
1433 1442
            while (id >= 0 && nodes[id].size == cmax) {
1434 1443
              int new_id = newNode();
1435 1444
              int left_id = nodes[id].left;
1436 1445

	
1437 1446
              popLeft(id);
1438 1447
              if (nodes[id].prio == nodes[left_id].prio) {
1439 1448
                setPrio(id);
1440 1449
              }
1441 1450
              push(new_id, left_id);
1442 1451
              pushLeft(new_id, ~(classes[l].parent));
1443
              setPrio(new_id);
1452

	
1453
              if (less(~classes[l].parent, left_id)) {
1454
                nodes[new_id].item = nodes[~classes[l].parent].item;
1455
                nodes[new_id].prio = nodes[~classes[l].parent].prio;
1456
              } else {
1457
                nodes[new_id].item = nodes[left_id].item;
1458
                nodes[new_id].prio = nodes[left_id].prio;
1459
              }
1444 1460

	
1445 1461
              id = nodes[id].parent;
1446 1462
              classes[l].parent = ~new_id;
1447 1463

	
1448 1464
            }
1449 1465
            if (id < 0) {
1450 1466
              int new_parent = newNode();
1451 1467
              nodes[new_parent].next = -1;
1452 1468
              nodes[new_parent].prev = -1;
1453 1469
              nodes[new_parent].parent = ~l;
1454 1470

	
1455 1471
              push(new_parent, ~(classes[r].parent));
1456 1472
              pushLeft(new_parent, ~(classes[l].parent));
1457 1473
              setPrio(new_parent);
1458 1474

	
1459 1475
              classes[r].parent = ~new_parent;
1460 1476
              classes[r].depth += 1;
1461 1477
            } else {
1462 1478
              pushLeft(id, ~(classes[l].parent));
1463 1479
              while (id >= 0 && less(~(classes[l].parent), id)) {
1464 1480
                nodes[id].prio = nodes[~(classes[l].parent)].prio;
1465 1481
                nodes[id].item = nodes[~(classes[l].parent)].item;
1466 1482
                id = nodes[id].parent;
1467 1483
              }
1468 1484
            }
1469 1485
            nodes[~(classes[r].parent)].parent = ~l;
1470 1486
            classes[l].parent = classes[r].parent;
1471 1487
            classes[l].depth = classes[r].depth;
1472 1488
          } else {
1473 1489
            if (classes[l].depth != 0 &&
1474 1490
                nodes[~(classes[l].parent)].size +
1475 1491
                nodes[~(classes[r].parent)].size <= cmax) {
1476 1492
              splice(~(classes[l].parent), ~(classes[r].parent));
1477 1493
              deleteNode(~(classes[r].parent));
1478 1494
              if (less(~(classes[r].parent), ~(classes[l].parent))) {
1479 1495
                nodes[~(classes[l].parent)].prio =
1480 1496
                  nodes[~(classes[r].parent)].prio;
1481 1497
                nodes[~(classes[l].parent)].item =
1482 1498
                  nodes[~(classes[r].parent)].item;
1483 1499
              }
1484 1500
            } else {
1485 1501
              int new_parent = newNode();
1486 1502
              nodes[new_parent].next = nodes[new_parent].prev = -1;
1487 1503
              push(new_parent, ~(classes[l].parent));
1488 1504
              pushRight(new_parent, ~(classes[r].parent));
1489 1505
              setPrio(new_parent);
1490 1506

	
1491 1507
              classes[l].parent = ~new_parent;
1492 1508
              classes[l].depth += 1;
1493 1509
              nodes[new_parent].parent = ~l;
1494 1510
            }
1495 1511
          }
1496 1512
          if (classes[r].next != -1) {
1497 1513
            classes[classes[r].next].prev = classes[r].prev;
1498 1514
          }
1499 1515
          classes[classes[r].prev].next = classes[r].next;
1500 1516

	
1501 1517
          classes[r].prev = classes[l].right;
1502 1518
          classes[classes[l].right].next = r;
1503 1519
          classes[l].right = r;
1504 1520
          classes[r].parent = l;
1505 1521

	
1506 1522
          classes[r].next = -1;
1507 1523
          classes[r].depth = rln;
0 comments (0 inline)