Explorar el Código

Getting segmentation fault from Delete at the height update which may be because of the DeleteMin function which has an implementation for BST, not AVL

Natalie Pueyo hace 8 años
padre
commit
67b97f288c
Se han modificado 5 ficheros con 152 adiciones y 49 borrados
  1. 17 48
      program3/AVLCommands.cpp
  2. 52 0
      program3/AVLSanityCheck.cxx
  3. 54 0
      program3/CreateData.cxx
  4. 12 1
      program3/Makefile
  5. 17 0
      program3/test.cpp

+ 17 - 48
program3/AVLCommands.cpp

@@ -1,14 +1,10 @@
-// written by Rob Gysel
-
-#include "AVLCommands.h"
-
 #include <cassert>
 #include <iostream>
 #include <string>
 #include <queue>
 
 #include "json.hpp"
-
+#include "AVLCommands.h"
 
 BSTNode::BSTNode(int key) :
 	key_(key),
@@ -65,49 +61,6 @@ void BSTNode::ReplaceChild(std::shared_ptr<BSTNode> v, std::shared_ptr<BSTNode>
 
 AVLCommands::AVLCommands() : root_(nullptr), size_(0) {} // add height here?
 
-// searches through the node keys to get the parent of specified key
-int AVLCommands::getParent(int key) {
-	int parent = 0;
-	if (root_ == nullptr) {
-		return -1;
-	}
-	std::shared_ptr<BSTNode> currentNode = root_, lastNode = nullptr;
-	while (currentNode->key_ != key) {
-		lastNode = currentNode;
-		currentNode = (key < currentNode->key_) ?
-			currentNode->left_ : currentNode->right_;
-	}
-	parent = lastNode -> key_;
-	return parent;
-}
-
-
-int AVLCommands::getLeft(int key) {
-	if (root_ == nullptr) {
-		return -1;
-	}
-	std::shared_ptr<BSTNode> currentNode = root_;
-	while (currentNode->key_ != key) {
-		currentNode = (key < currentNode->key_) ?
-			currentNode->left_ : currentNode->right_;
-	}
-	currentNode = currentNode->left_;
-	return currentNode->key_;
-}
-
-int AVLCommands::getRight(int key) {
-	if (root_ == nullptr) {
-		return -1;
-	}
-	std::shared_ptr<BSTNode> currentNode = root_;
-	while (currentNode->key_ != key) {
-		currentNode = (key < currentNode->key_) ?
-			currentNode->left_ : currentNode->right_;
-	}
-	currentNode = currentNode->right_;
-	return currentNode->key_;
-}
-
 int AVLCommands::max(int a, int b) {
 	return (a > b)? a : b;
 }
@@ -177,10 +130,16 @@ void AVLCommands::Insert(int key) {
 	size_++;
 
 	// Update hight of this ancestor's node... need to check if this should be currNode or lastNode
+	std::cout << "insert height update attempt..." << std::endl;
 	lastNode->height_ = 1 + max(height(lastNode->left_), height(lastNode->right_));
+	std::cout << "New height: " << lastNode->height_ << std::endl;
+	std::cout << "insert height update attempt success!" << std::endl;
 
 	// Update balance factor of this ancestor's node
+	std::cout << "insert balance update attempt..." << std::endl;
 	int lastNodeBalance = getBalance(lastNode);
+	std::cout << "New balance: " << lastNodeBalance << std::endl;
+	std::cout << "insert balance update attempt success!" << std::endl;
 
 	// Check if unbalanced
 	// Left Left Case
@@ -229,11 +188,17 @@ bool AVLCommands::Delete(int key) {
 			currentNode->left_ : currentNode->right_;
 	}
 
+	std::cout << "current node value: " << currentNode->key_ << std::endl;
 	// update height of current node
+	std::cout << "delete height update attempt..." << std::endl;
 	currentNode->height_ = 1 + max(height(currentNode->left_), height(currentNode->right_));
+	std::cout << "New height: " << currentNode->height_ << std::endl;
+	std::cout << "delete height update attempt success" << std::endl;
 
 	// Update balance factor of this ancestor's node
+	std::cout << "delete balance update attempt..." << std::endl;
 	int currentNodeBalance = getBalance(currentNode);
+	std::cout << "delete balance update attempt success!" << std::endl;
 
 	// Check if unbalanced
 	// Left Left Case
@@ -258,6 +223,7 @@ bool AVLCommands::Delete(int key) {
 	return false;
 }
 
+
 int AVLCommands::DeleteMin() {
 	return DeleteMin(root_);
 }
@@ -340,6 +306,9 @@ std::string AVLCommands::JSON() const {
 			auto v = nodes.front();
 			nodes.pop();
 			std::string key = std::to_string(v->key_);
+			std::string height = std::to_string(v->height_);
+			result[key]["height"] = height;
+			result[key]["left"] = v->left_->key_;
 			if (v->left_ != nullptr) {
 				result[key]["left"] = v->left_->key_;
 				nodes.push(v->left_);

+ 52 - 0
program3/AVLSanityCheck.cxx

@@ -0,0 +1,52 @@
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+#include <random>
+#include <vector>
+
+#include "AVLCommands.h"
+
+#define SAMPLE_SIZE 1000
+#define NUM_TESTS 10000
+
+int main() {
+
+	// C++11 random number tutorial: https://gist.github.com/PhDP/5289449
+	// Seed random number generator
+	std::mt19937_64 rng(time(0));
+	// Create uniform distribution
+	std::uniform_int_distribution<int> unif(
+		std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
+	std::uniform_int_distribution<int> op(0,10);
+
+	std::vector<int> sampleData, BSTSortedData;
+	sampleData.reserve(SAMPLE_SIZE);
+	BSTSortedData.reserve(SAMPLE_SIZE);
+	std::cout << "Running tests..." << std::flush;
+	for (unsigned int sample = 0; sample < NUM_TESTS; sample++) {
+		AVLCommands T;
+		// On size_t usage here: https://stackoverflow.com/questions/131803/unsigned-int-vs-size-t
+		for (size_t i = 0; i < SAMPLE_SIZE; i++) {
+			if (op(rng) == 0 && !T.empty()) {
+				T.Delete(sampleData.back());
+				sampleData.pop_back();
+			} else {
+				// Add random integer to array
+				int x = unif(rng);
+				T.Insert(x);
+				sampleData.push_back(x);
+			}
+		}
+		while (!T.empty()) {
+			BSTSortedData.push_back(T.DeleteMin());
+		}
+		std::sort(sampleData.begin(), sampleData.end());
+		assert(sampleData == BSTSortedData);
+		BSTSortedData.clear();
+		sampleData.clear();
+		if (sample % (NUM_TESTS / 10) == 0) {
+			std::cout << "." << std::flush;
+		}
+	}
+	std::cout << "Tests complete.\n";
+}

+ 54 - 0
program3/CreateData.cxx

@@ -0,0 +1,54 @@
+#include <algorithm>
+#include <iostream>
+#include <random>
+#include <vector>
+
+#include "json.hpp"
+
+int main(int argc, char** argv) {
+	if (argc != 2) {
+		std::cerr << "Usage: " << argv[0] << "numOps" << std::endl;
+		exit(EXIT_FAILURE);
+	}
+	unsigned int numOps = 0;
+	if (sscanf(argv[1], "%d", &numOps) != 1 || numOps == 0) {
+		std::cerr << "Usage: " << argv[0] << "numOps" << std::endl;
+		std::cerr << "numOps must be a positive integer" << std::endl;
+		exit(EXIT_FAILURE);
+	}
+	// C++11 random number tutorial: https://gist.github.com/PhDP/5289449
+	// Seed random number generator
+	std::mt19937_64 rng(time(0));
+	// Create uniform distribution
+	std::uniform_int_distribution<int> unif(
+		std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
+	std::uniform_int_distribution<int> opDist(0,10);
+	nlohmann::json result;
+	std::vector<int> keys;
+	result["metadata"]["numOps"] = numOps;
+	unsigned int totalZeros = (int) floor(log10((double) numOps)) + 1;
+	for (size_t op = 1; op <= numOps; op++) {
+		int operation = opDist(rng);
+		int opDigits = (int) floor(log10((double) op)) + 1;
+		std::string opKey = std::string(totalZeros - opDigits, '0')
+			.append(std::to_string(op));
+		if (operation == 0 && !keys.empty()) {
+			result[opKey] = nlohmann::json();
+			result[opKey]["operation"] = "Delete";
+			result[opKey]["key"] = keys.back();
+			keys.pop_back();
+		} else if (operation == 1 && !keys.empty()) {
+			result[opKey] = nlohmann::json();
+			result[opKey]["operation"] = "DeleteMin";
+			std::sort(keys.rbegin(), keys.rend());
+			keys.pop_back();
+		} else {
+			int x = unif(rng);
+			result[opKey] = nlohmann::json();
+			result[opKey]["operation"] = "Insert";
+			result[opKey]["key"] = x;
+			keys.push_back(x);
+		}
+	}
+	std::cout << result.dump(2) << std::endl;
+}

+ 12 - 1
program3/Makefile

@@ -2,8 +2,10 @@ CC=g++
 DEV=-Wall -g -std=c++14
 OPT=-O3 -std=c++14
 
+JSON=json.hpp
+
 .PHONY: all
-all: BSTSanityCheck CreateData
+all: BSTSanityCheck CreateData AVLSanityCheck Test
 
 CreateData: CreateData.cxx json.hpp
 	$(CC) $(OPT) CreateData.cxx -o CreateData
@@ -11,9 +13,18 @@ CreateData: CreateData.cxx json.hpp
 BSTSanityCheck: BSTSanityCheck.cxx BST.o
 	$(CC) $(DEV) BSTSanityCheck.cxx BST.o -o BSTSanityCheck
 
+AVLSanityCheck: AVLSanityCheck.cxx AVLCommands.o
+	$(CC) $(DEV) AVLSanityCheck.cxx AVLCommands.o -o AVLSanityCheck
+
+Test: test.cpp AVLCommands.o
+	$(CC) $(DEV) test.cpp AVLCommands.o -o Test
+
 BST.o: BST.cpp BST.h
 	$(CC) $(DEV) -c BST.cpp
 
+AVLCommands.o: AVLCommands.cpp AVLCommands.h
+	$(CC) $(DEV) -c AVLCommands.cpp
+
 # Build
 .PHONY: clean
 clean:

+ 17 - 0
program3/test.cpp

@@ -0,0 +1,17 @@
+// Driver program to test above functions
+#include "AVLCommands.h"
+
+int main()
+{
+    AVLCommands avl;
+    avl.Insert(3);
+    avl.Insert(50);
+    avl.Insert(1);
+    avl.Insert(15);
+    avl.Insert(2);
+    avl.Insert(5);
+    avl.Insert(20);
+    avl.Insert(50);
+    avl.Delete(15);
+    return 0;
+}