int merge_left (PBTREE btree, int node_idx, int parent_index_this) { // copy all elements from this node into the left sibling, along with the // element in the parent node vector that has this node as its subtree. // this node and its parent element are then deleted. int i; int parent_node_idx = btree->nodes[node_idx].parent_node_idx; BTREE_ELEMENT parent_elem; memcpy(&parent_elem, &btree->nodes[parent_node_idx].elements[parent_index_this], sizeof(BTREE_ELEMENT)); int left_sib = btree->nodes[parent_node_idx].elements[parent_index_this-1].subtree_node_idx; parent_elem.subtree_node_idx = btree->nodes[node_idx].elements[0].subtree_node_idx; vector_insert (btree, left_sib, &parent_elem); for (i=1; i<btree->nodes[node_idx].element_count; i++) vector_insert (btree, left_sib, &btree->nodes[node_idx].elements[i]); vector_delete_pos (btree, parent_node_idx, parent_index_this); if (parent_node_idx==find_root(btree) && !key_count(btree, parent_node_idx)) { set_root(btree, left_sib); delete_node(btree, parent_node_idx); btree->nodes[left_sib].parent_node_idx = BTREE_INVALID_NODE_IDX; delete_node(btree, node_idx); return BTREE_INVALID_NODE_IDX; } else if (parent_node_idx==find_root(btree) && key_count(btree, parent_node_idx)) { delete_node(btree, node_idx); return BTREE_INVALID_NODE_IDX; } delete_node(btree, node_idx); if (key_count(btree, parent_node_idx) >= btree_minimum_keys()) return BTREE_INVALID_NODE_IDX; // no need for parent to import an element return parent_node_idx; // parent must import an element }
int btree_delete_ex (PBTREE btree, int node_idx, long target_key) { // target is just a package for the key value. the reference does not // provide the address of the Elem instance to be deleted. // first find the node contain the Elem instance with the given key int parent_index_this = BTREE_INVALID_ELEMENT_IDX; PBTREE_ELEMENT found; int last_visted_node_idx; if (node_idx == BTREE_INVALID_NODE_IDX) node_idx = btree->root_node_idx; last_visted_node_idx = node_idx; found = btree_search_ex (btree, &last_visted_node_idx, target_key); if (!found) return 0; if (is_leaf(btree, last_visted_node_idx) && key_count(btree, last_visted_node_idx) > btree_minimum_keys()) return vector_delete (btree, last_visted_node_idx, target_key); else if (is_leaf(btree, last_visted_node_idx)) { vector_delete (btree, last_visted_node_idx, target_key); // loop invariant: if _node_ is not null_ptr, it points to a node // that has lost an element and needs to import one from a sibling // or merge with a sibling and import one from its parent. // after an iteration of the loop, _node_ may become null or // it may point to its parent if an element was imported from the // parent and this caused the parent to fall below the minimum // element count. while (BTREE_IS_VALID_NODE_IDX(last_visted_node_idx)) { int right, left; // NOTE: the "this" pointer may no longer be valid after the first // iteration of this loop!!! if (last_visted_node_idx == find_root(btree) && is_leaf(btree, last_visted_node_idx)) break; if (last_visted_node_idx == find_root(btree) && !is_leaf(btree, last_visted_node_idx)) // sanity check return 0; // is an extra element available from the right sibling (if any) right = right_sibling(btree, last_visted_node_idx, &parent_index_this); if (BTREE_IS_VALID_NODE_IDX(right) && key_count(btree, right) > btree_minimum_keys()) last_visted_node_idx = rotate_from_right(btree, last_visted_node_idx, parent_index_this); else { // is an extra element available from the left sibling (if any) left = left_sibling(btree, last_visted_node_idx, &parent_index_this); if (BTREE_IS_VALID_NODE_IDX(left) && key_count(btree, left) > btree_minimum_keys()) last_visted_node_idx = rotate_from_left(btree, last_visted_node_idx, parent_index_this); else if (BTREE_IS_VALID_NODE_IDX(right)) last_visted_node_idx = merge_right(btree, last_visted_node_idx, parent_index_this); else if (BTREE_IS_VALID_NODE_IDX(left)) last_visted_node_idx = merge_left(btree, last_visted_node_idx, parent_index_this); } } } else { PBTREE_ELEMENT smallest_in_subtree = smallest_key_in_subtree(btree, found->subtree_node_idx); found->key = smallest_in_subtree->key; found->data_entry_idx = smallest_in_subtree->data_entry_idx; btree_delete_ex (btree, found->subtree_node_idx, smallest_in_subtree->key); } return 1; }
int main(int argc, char* argv[]) { Table t; /* Initialize the table */ init_table(&t); /* Insert into the table */ test_assert(key_count(&t) == 0, "insert", 0); test_assert(!insert(&t, "202", "DC"), "insert", 1); test_assert(!insert(&t, "301", "W_MD"), "insert", 2); test_assert(key_count(&t) == 2, "insert", 3); return 0; }
int main(int argc, char* argv[]) { Table t; /* Initialize the table */ init_table(&t); /* Insert into the table */ test_assert(key_count(&t) == 0, "insert", 0); test_assert(!insert(&t, "202", "DC"), "insert", 1); test_assert(key_count(&t) == 1, "insert", 2); /* Delete from the table */ test_assert(!delete(&t, "202"), "delete", 3); test_assert(key_count(&t) == 0, "delete", 4); return 0; }
int main(int argc, char* argv[]) { Table t; char str[10]; /* Initialize the table */ init_table(&t); /* Search for non-existent entries */ test_assert(key_count(&t) == 0, "key_count", 0); test_assert(!insert(&t, "Jack", "2278"), "insert", 1); test_assert(!insert(&t, "Mike", "2056"), "insert", 2); test_assert(key_count(&t) == 2, "key_count", 3); test_assert(search(&t, "Fred", str), "delete", 4); test_assert(key_count(&t) == 2, "key_count", 5); return 0; }
int main(int argc, char* argv[]){ int index; Table t; const char key[26] ={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; init_table(&t); for(index = 0; index < 26; index++){ /* Insert into the table */ insert(&t, key[index], "DC"); } test_assert(key_count(&t) == 26, "key_count", 0); return 0; }
//search for Element have greatest value less than desired... template<class KEY, class VALUE> Elem& Nde::searchGL(Elem& desired) { // the zeroth element of the vector is a special case (no key value or // payload, just a subtree). the seach starts at the *this node, not // at the root of the b-tree. Nde* current = this; if (!key_count()){ current = 0;} while (current) { // desired less than all values in current node if (current->m_count>1 && desired<current->m_vector[1]){ current = current->m_vector[0].mp_subtree; // desired greater than all values in current node } else if (desired>current->m_vector[current->m_count-1]){ if(!current->m_vector[current->m_count-1].mp_subtree) //ABOVE ALL LEAVES CASE //We're at the end of the sequence { return current->m_vector[current->m_count-1]; } else {current = current->m_vector[current->m_count-1].mp_subtree;} } else { // binary search of the node int first = 1; int last = current->m_count-1; while (last-first > 1) { int mid = first+(last-first)/2; if (desired>=current->m_vector[mid]){ first = mid;} else{ last = mid;} } //Exact MATCH TO LEAF CASES if(current->m_vector[first]==desired) {return current->m_vector[first];} if(current->m_vector[last]==desired) {return current->m_vector[last];} //BETWEEN TWO LEAVES CASE //within an interval on level last = first +1 !! if(!current->m_vector[first].mp_subtree && !current->m_vector[last].mp_subtree){ return current->m_vector[first]; } Elem& lGelem = current->m_vector[last].mp_subtree->smallest_key_in_subtree(); if(desired < lGelem) { current = current->m_vector[last].mp_subtree; } else { current = current->m_vector[first].mp_subtree; } } } //BELOW ALL LEAVES CASE return m_failure; }
PBTREE_ELEMENT btree_search_ex (PBTREE btree, int *node_idx, long desired_key) { // the zeroth element of the vector is a special case (no key value or // payload, just a subtree). the seach starts at the *this node, not // at the root of the b-tree. int current_node_idx = *node_idx; if (!key_count(btree, *node_idx)) current_node_idx = BTREE_INVALID_NODE_IDX; while (BTREE_IS_VALID_NODE_IDX(current_node_idx)) { *node_idx = current_node_idx; // if desired is less than all values in current node if (btree->nodes[current_node_idx].element_count>1 && desired_key < btree->nodes[current_node_idx].elements[1].key) current_node_idx = btree->nodes[current_node_idx].elements[0].subtree_node_idx; // if desired is greater than all values in current node else if (desired_key > btree->nodes[current_node_idx].elements[btree->nodes[current_node_idx].element_count-1].key) current_node_idx = btree->nodes[current_node_idx].elements[btree->nodes[current_node_idx].element_count-1].subtree_node_idx; else { // binary search of the node int first = 1; int last = btree->nodes[current_node_idx].element_count-1; while (last-first > 1) { int mid = first+(last-first)/2; if (desired_key >= btree->nodes[current_node_idx].elements[mid].key) first = mid; else last = mid; } if (btree->nodes[current_node_idx].elements[first].key == desired_key) return &btree->nodes[current_node_idx].elements[first]; if (btree->nodes[current_node_idx].elements[last].key == desired_key) return &btree->nodes[current_node_idx].elements[last]; else if (btree->nodes[current_node_idx].elements[last].key > desired_key) current_node_idx = btree->nodes[current_node_idx].elements[first].subtree_node_idx; else current_node_idx =btree->nodes[current_node_idx].elements[last].subtree_node_idx; } } return NULL; }
template<class KEY, class VALUE> Elem& Nde::search (Elem& desired, Nde*& last_visited_ptr) { // the zeroth element of the vector is a special case (no key value or // payload, just a subtree). the seach starts at the *this node, not // at the root of the b-tree. Nde* current = this; if (!key_count()){ current = 0;} while (current) { last_visited_ptr = current; // if desired is less than all values in current node if (current->m_count>1 && desired<current->m_vector[1]) current = current->m_vector[0].mp_subtree; // if desired is greater than all values in current node else if (desired>current->m_vector[current->m_count-1]) current = current->m_vector[current->m_count-1].mp_subtree; else { // binary search of the node int first = 1; int last = current->m_count-1; while (last-first > 1) { int mid = first+(last-first)/2; if (desired>=current->m_vector[mid]) first = mid; else last = mid; } if (current->m_vector[first]==desired) return current->m_vector[first]; if (current->m_vector[last]==desired) return current->m_vector[last]; else if (current->m_vector[last]>desired) current = current->m_vector[first].mp_subtree; else current = current->m_vector[last].mp_subtree; } } return m_failure; }
/************************************************************** * main takes in a number of arguments, for this project only * * 1 or 2 arguments is considered valid. If there is only one * * argument, we will treat stdin as the input source. If there * * are two arguments, we will treat the second argument as a * * data file that commands may be read from. * **************************************************************/ int main(int argc, char *argv[]){ FILE *input; char line[MAX_LEN + 1], first_word[MAX_LEN + 1], second_word[MAX_LEN + 1] , val[MAX_LEN + 1]; Table t; int index; init_table(&t); /* If only one argument is present, command line input will be used.*/ if(argc == 1){ input = stdin; /* IF two arguments are present, the second argument is taken to be a data file.*/ } else if(argc == 2){ input = fopen(argv[1], "r"); /*If the file cannot be opened, an error message will be printed, and the program will exit. */ if(input == NULL){ fprintf(stderr, "File %s open failed. Error: %s.\n", argv[1], strerror(errno)); exit(EX_OSERR); } /*If there are more than two arguments present, an error message will be printed, and the program will exit.*/ } else{ fprintf(stderr, "Too many input arguments. Error : %s.\n", strerror(errno)); exit(EX_USAGE); } /* As fgets reads in each line of the input, sscanf reads the first word of each line and assigns it to first_word.*/ while (fgets(line, MAX_LEN + LEN_EXTRA, input) != NULL) { /*If a line is too long, an error message is printed out, and the program exits.*/ if(strlen(line) > MAX_LEN){ fprintf(stderr, "Line is greater than 1024 characters. Error: %s.\n", strerror(errno)); exit(EX_DATAERR); } sscanf(line, "%s", first_word); /*If we have a blank line, we skip it.*/ if(strcmp(line, "\n") == 0){ continue; } /*If the first non-whitespace character is a '#', this line is a comment, and we skip it.*/ else if(first_word[0] == '#'){ continue; /*If the first word in a line is "insert" and all arguments are present, we attempt to insert a key/value pair*/ }else if(strcmp(first_word, "insert") == 0 && sscanf(line, "%s %s %s", first_word, second_word, val) == INSERT_ARGS){ /*If the insertion is successful, we print the success message*/ if(insert(&t, second_word, val) == 0){ printf("Insertion of %s => %s succeeded.\n", second_word, val); /*Otherwise, we print the failure message.*/ } else{ printf("Insertion of %s => %s failed.\n", second_word, val); } /*If the first word of a line is "search" and both arguments are present, we attempt to search for a key in the table.*/ } else if(strcmp(first_word, "search") == 0 && sscanf(line, "%s %s", first_word, second_word) == SEARCH_ARGS){ /*If the search succeeds, we print the success message*/ if(search(&t, second_word, val) == 0){ printf("Search for %s succeeded (%s).\n", second_word, val); /*If the search fails, we print the failure message.*/ } else{ printf("Search for %s failed.\n", second_word); } /*If the first word in the line is "delete" and both arguments are present, we attempt to delete a key from the table. */ } else if(strcmp(first_word, "delete") == 0 && sscanf(line, "%s %s", first_word, second_word) == DELETE_ARGS){ /*If the deletion succeeds, we print out the success message.*/ if(delete(&t, second_word) == 0){ printf("Deletion of %s succeeded.\n", second_word); /*If the deletion fails, we print out the ffailure message.*/ } else{ printf("Deletion of %s failed.\n", second_word); } /*If the first word in a line is "reset", we attempt to reset the table.*/ }else if(strcmp(first_word, "reset") == 0){ /*Reset the table, then print success message.*/ reset_table(&t); printf("Table reset.\n"); /*If the first word in a line is "display" and both arguments are present, we display either the contents of the table or the key count.*/ } else if(strcmp(first_word, "display") == 0 && sscanf(line, "%s %s", first_word, second_word) == DISPLAY_ARGS){ /*If the item to display is key count we attempt to display the key_count.*/ if(strcmp(second_word, "key_count") == 0){ /*If key_count succeeds, the key count will be printed, otherwise 0 will be printed. */ if(key_count(&t) != -1){ printf("Key count: %d\n", key_count(&t)); } else{ printf("Key count: 0\n"); } /*If the item to be displayed is the table, we will attempt to print out the contents of the table. */ } else if(strcmp(second_word, "table") == 0){ /*We iterate through the table and print out the bucket number, state, and (if the bucket is full) its key and value.*/ for(index = 0; index < NUM_BUCKETS; index++){ if(t.buckets[index].state == EMPTY){ printf("Bucket %d: EMPTY\n", index); } else if(t.buckets[index].state == DELETED){ printf("Bucket %d: DELETED\n", index); } else{ printf("Bucket %d: FULL (%s => %s)\n", index, t.buckets[index].data.key, t.buckets[index].data.value); } } } /*If an invalid line is found we print out an error message and exit.*/ } else{ fprintf(stderr, "Invalid line found, retry with valid command, comment, or empty line. Error: %s.\n", strerror(errno)); exit(EX_DATAERR); } } /*When we are done, we close the file and return 0.*/ fclose(input); return 0; }