Forráskód Böngészése

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 8 éve
szülő
commit
67b97f288c
5 módosított fájl, 152 hozzáadás és 49 törlés
  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;
+}