Startpunkten
This commit is contained in:
76
AVL_tree/header.hpp
Normal file
76
AVL_tree/header.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
//##################################################################
|
||||
// PROGRAMMERINGSUPPGIFT 2
|
||||
// DATASTRUKTURER OCH ALGORITMER
|
||||
// AVL TRÄD
|
||||
//==================================================================
|
||||
// HEADER.HPP
|
||||
// Filen innehåller definition som används i programmet
|
||||
// Christian Ohlsson
|
||||
// Karlstad 980927
|
||||
//==================================================================
|
||||
#ifndef _header_
|
||||
#define _header_
|
||||
|
||||
#include <iostream.h>
|
||||
#include <fstream.h>
|
||||
#include <iomanip.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
//#include <conio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
const int FALSE = 0; //boolsk variabel
|
||||
const int TRUE = !FALSE; //boolsk variabel
|
||||
const int BUFFERSIZE = 100; //för säker inmatning
|
||||
const int FILENAMESIZE = 8; //för MS-DOS 6.0
|
||||
const int NAMESIZE = 20; //antal tecken som kan matas in som namn
|
||||
const int NUMBERSIZE = 20; //antal tecken som kan matas in som nummer
|
||||
const int ENTER = 13; //ASCII kod för enter
|
||||
const int BACKSPACE = 8; //ASCII kod för backspace
|
||||
|
||||
//typedef int bool; //definierar boolsk variabel
|
||||
typedef char nameType[NAMESIZE]; //sätter nametypen till char
|
||||
typedef char numberType[NUMBERSIZE]; //sätter numberTypen till char
|
||||
struct treeNode; //förvarnar datorn om en struct
|
||||
typedef treeNode* ptrType; //ger en pekartype till en struct
|
||||
struct treeNode{ //en nod i trädet
|
||||
|
||||
nameType name;
|
||||
numberType number;
|
||||
ptrType left;
|
||||
ptrType right;
|
||||
int height;
|
||||
treeNode(nameType oneName,numberType number,
|
||||
ptrType left, ptrType right,
|
||||
int height);
|
||||
};
|
||||
|
||||
class treeClass
|
||||
{
|
||||
public:
|
||||
treeClass();
|
||||
~treeClass(){};
|
||||
ptrType node;
|
||||
ptrType seek(ptrType node, nameType value);
|
||||
bool isEmpty();
|
||||
void destroyTree(ptrType &node);
|
||||
void setHeight(ptrType &node);
|
||||
void rotation(ptrType &node);
|
||||
void inOrder(ptrType treeNode);
|
||||
void del(ptrType &node, nameType oneName);
|
||||
void insert(ptrType &node,nameType oneName,numberType number, int height);
|
||||
void save(ptrType node, fstream &fil);
|
||||
private:
|
||||
int balance(ptrType &node);
|
||||
int maxHeight(ptrType &node);
|
||||
int size;
|
||||
void singleLeft(ptrType &node);
|
||||
void singleRight(ptrType &node);
|
||||
void doubleRL(ptrType &node);
|
||||
void doubleLR(ptrType &node);
|
||||
void delLeft(ptrType &node, nameType oneName, numberType oneNumber);
|
||||
void delRoot(ptrType &node);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
273
AVL_tree/huvud.cpp
Normal file
273
AVL_tree/huvud.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
//##################################################################
|
||||
// PROGRAMMERINGSUPPGIFT 2
|
||||
// DATASTRUKTURER OCH ALGORITMER
|
||||
// AVL TRÄD
|
||||
//==================================================================
|
||||
// HUVUD.CPP
|
||||
// Filen innehåller huvudprogrammet
|
||||
// Christian Ohlsson
|
||||
// Karlstad 980927
|
||||
//==================================================================
|
||||
|
||||
#include "header.hpp"
|
||||
|
||||
//###############################################################
|
||||
// SÄKER INMATNING AV MENYVAL
|
||||
// ser till att bara en character matas in
|
||||
// som menyval som dessutom måste vara en siffra
|
||||
//===============================================================
|
||||
/*
|
||||
char mataInChar()
|
||||
{
|
||||
bool test = FALSE;
|
||||
char temp, svar;
|
||||
do {
|
||||
temp = getch();
|
||||
if(isalnum(temp) && test == FALSE) {
|
||||
cout << temp;
|
||||
svar = temp;
|
||||
test = TRUE;
|
||||
}
|
||||
else if(temp == BACKSPACE && test == TRUE) {
|
||||
gotoxy(wherex()-1, wherey());
|
||||
cout << " ";
|
||||
gotoxy(wherex()-1, wherey());
|
||||
test = FALSE;
|
||||
}
|
||||
}while(temp != ENTER || test == FALSE);
|
||||
return svar;
|
||||
}
|
||||
*/
|
||||
//##################################################################
|
||||
// SÄTTER IN EN NOD I TRÄD
|
||||
// calls: treeClass::insert, treeclass::seek, treeClass::setHeight
|
||||
// treeClass::rotation
|
||||
//==================================================================
|
||||
void _insert(treeClass &myTree)
|
||||
{
|
||||
nameType oneName;
|
||||
numberType number;
|
||||
int height=0;
|
||||
|
||||
cout <<"\n Ange namn: ";
|
||||
cin >> oneName;
|
||||
if(strlen(oneName) > NAMESIZE)
|
||||
cout << "\n Man kan högst ange namnet med " << NAMESIZE << " tecken";
|
||||
else {
|
||||
if(myTree.seek(myTree.node, oneName) != NULL)
|
||||
cout << "\n Du har redan satt in "
|
||||
<< oneName << " i katalogen";
|
||||
else {
|
||||
cout <<"\n Ange telefonnummer: ";
|
||||
cin >> number;
|
||||
if (strlen(number) > NUMBERSIZE)
|
||||
cout << "\n Man kan högst ange nummret med " << NUMBERSIZE << " tecken";
|
||||
else {
|
||||
myTree.insert(myTree.node,oneName,number,height);
|
||||
myTree.setHeight(myTree.node);
|
||||
myTree.rotation(myTree.node);
|
||||
myTree.setHeight(myTree.node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// getch();
|
||||
}
|
||||
//##################################################################
|
||||
// TAR BORT EN NOD UR TRÄD
|
||||
// calls: treeClass::del, treeClass::isEmpty, treeclass::seek
|
||||
// treeClass::setHeight, treeClass::rotation
|
||||
//==================================================================
|
||||
void _del(treeClass &myTree)
|
||||
{
|
||||
if(!myTree.isEmpty()) {
|
||||
nameType oneName;
|
||||
|
||||
cout << "\n Vem vill du ta bort: ";
|
||||
cin >> oneName;
|
||||
if(strlen(oneName) > NAMESIZE)
|
||||
cout << "\n Man kan högst ange namnet med " << NAMESIZE << " tecken";
|
||||
else {
|
||||
if(myTree.seek(myTree.node, oneName) == NULL)
|
||||
cerr << "\n " << oneName << " finns inte i katalogen. ";
|
||||
else {
|
||||
myTree.del(myTree.node, oneName);
|
||||
myTree.setHeight(myTree.node);
|
||||
myTree.rotation(myTree.node);
|
||||
myTree.setHeight(myTree.node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
cerr << "\n Telefonkatalogen är tom... ";
|
||||
// getch();
|
||||
}
|
||||
//##################################################################
|
||||
// SKRIVER UT I INORDER
|
||||
// calls: treeClass::inOrder, treeClass::isEmpty
|
||||
//==================================================================
|
||||
void _inOrder(treeClass myTree)
|
||||
{
|
||||
if(!myTree.isEmpty()) {
|
||||
// clrscr();
|
||||
cout << setw(NAMESIZE)
|
||||
<< "Namn"
|
||||
<< setw(NAMESIZE)
|
||||
<< "Telefon"
|
||||
<< setw(NAMESIZE)
|
||||
<< "Höjd \n"
|
||||
<< setw(NAMESIZE)
|
||||
<< " ------------------------------------------------------------------ \n";
|
||||
myTree.inOrder(myTree.node);
|
||||
}
|
||||
else
|
||||
cerr << "\n Telefonkatalogen är tom... ";
|
||||
// getch();
|
||||
}
|
||||
//##################################################################
|
||||
// SÖKER I TRÄDET
|
||||
// calls: treeClass::seek, treeClass::isEmpty
|
||||
//==================================================================
|
||||
void _seek(treeClass myTree)
|
||||
{
|
||||
if(!myTree.isEmpty()) {
|
||||
nameType oneName;
|
||||
cout << "\n Mata in namn: ";
|
||||
cin >> oneName;
|
||||
ptrType tempNode = myTree.seek(myTree.node, oneName);
|
||||
if(tempNode != NULL)
|
||||
cout << "\n " << tempNode->name
|
||||
<< " har telefonnummer: "
|
||||
<< tempNode->number;
|
||||
else
|
||||
cout << "\n " << oneName << " fanns inte med i katalogen...";
|
||||
}
|
||||
else
|
||||
cerr << "\n Telefonkatalogen är tom... ";
|
||||
// getch();
|
||||
}
|
||||
//##################################################################
|
||||
// SPARAR TRÄDET PÅ FIL
|
||||
// calls: treeClass::save, treeClass::isEmpty
|
||||
//==================================================================
|
||||
void _save(treeClass myTree)
|
||||
{
|
||||
if(!myTree.isEmpty()) {
|
||||
fstream fil;
|
||||
char filnamn[FILENAMESIZE];
|
||||
cout << "\n Ange filnamn att spara: ";
|
||||
cin >> filnamn;
|
||||
fil.open(filnamn,ios::out|ios::binary);
|
||||
myTree.save(myTree.node, fil);
|
||||
fil.close();
|
||||
}
|
||||
else {
|
||||
cerr << "\n Telefonkatalogen är tom...";
|
||||
// getch();
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
// HÄMTAR ETT TRÄD FRÅN EN FIL
|
||||
// läser in värdet i varje nod i preorder
|
||||
// och sätter in det i trädet i preoder
|
||||
// calls treeClass::insert, treeClass::isEmpty, treeClass::setHeight
|
||||
// treeClass::rotation
|
||||
//==================================================================
|
||||
void _load(treeClass &myTree)
|
||||
{
|
||||
if(myTree.isEmpty()) {
|
||||
fstream fil;
|
||||
numberType number;
|
||||
nameType oneName;
|
||||
char filnamn[FILENAMESIZE];
|
||||
|
||||
cout << "\n Ange filnamn att hämta: ";
|
||||
cin >> filnamn;
|
||||
fil.open(filnamn,ios::in|ios::binary);
|
||||
if(fil)
|
||||
while(fil.peek() != EOF) {
|
||||
fil.read((char*)&oneName,sizeof(oneName));
|
||||
fil.read((char*)&number,sizeof(number));
|
||||
myTree.insert(myTree.node, oneName,number,0);
|
||||
myTree.setHeight(myTree.node);
|
||||
myTree.rotation(myTree.node);
|
||||
myTree.setHeight(myTree.node);
|
||||
}
|
||||
else {
|
||||
cerr << "\n Filen finns inte...";
|
||||
// getch();
|
||||
}
|
||||
fil.close();
|
||||
}
|
||||
else {
|
||||
cerr << "\n Det finns redan personer i katalogen. \n"
|
||||
<< " Du måste ta bort samtliga personer \n"
|
||||
<< " genom att välja detta i menyn. \n";
|
||||
// getch();
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
// DESTROYTREE
|
||||
// tar bort hela trädet
|
||||
// calls: treeClass::isEmpty, treeClass::destroyTree
|
||||
//==================================================================
|
||||
void _destroyTree(treeClass &myTree)
|
||||
{
|
||||
if(!myTree.isEmpty())
|
||||
myTree.destroyTree(myTree.node);
|
||||
else {
|
||||
cerr << "\n Telefonkatalogen är tom...";
|
||||
// getch();
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
// MENY ITEMS
|
||||
// skriver ut menyn på skärmen
|
||||
//==================================================================
|
||||
void meny()
|
||||
{
|
||||
// clrscr();
|
||||
cout << " \n TELEFON KATALOGEN "
|
||||
<< " \n ----------------- "
|
||||
<< " \n 1. Lägg till person "
|
||||
<< " \n 2. Ta bort person "
|
||||
<< " \n 3. Sök efter person "
|
||||
<< " \n 4. Skriv ut i bokstavsordning "
|
||||
<< " \n 5. Spara på fil "
|
||||
<< " \n 6. Hämta från fil "
|
||||
<< " \n 7. Radera hela trädet "
|
||||
<< " \n 0. Avsluta "
|
||||
<< " \n ";
|
||||
// gotoxy(2,12); //ställer markören under menyn
|
||||
}
|
||||
//##################################################################
|
||||
// MAIN FUNCTION
|
||||
// skapar trädet myTree av typen treeClass
|
||||
// calls: alla drivrutiner
|
||||
//==================================================================
|
||||
void main()
|
||||
{
|
||||
treeClass myTree;
|
||||
char val;
|
||||
do {
|
||||
meny();
|
||||
cin >> val;
|
||||
// val = mataInChar();;
|
||||
switch (val)
|
||||
{
|
||||
case '1' : _insert(myTree);break;
|
||||
case '2' : _del(myTree);break;
|
||||
case '3' : _seek(myTree);break;
|
||||
case '4' : _inOrder(myTree);break;
|
||||
case '5' : _save(myTree);break;
|
||||
case '6' : _load(myTree);break;
|
||||
case '7' : _destroyTree(myTree);break;
|
||||
case '0' : cout << "\n Programmet avslutat";break;
|
||||
default : cerr << "\n Felaktigt val";
|
||||
// getch();
|
||||
}
|
||||
}while(val != '0');
|
||||
}
|
||||
|
||||
|
||||
BIN
AVL_tree/run_me
Normal file
BIN
AVL_tree/run_me
Normal file
Binary file not shown.
344
AVL_tree/tree.cpp
Normal file
344
AVL_tree/tree.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
//##################################################################
|
||||
// PROGRAMMERINGSUPPGIFT 2
|
||||
// DATASTRUKTURER OCH ALGORITMER
|
||||
// AVL TRÄD
|
||||
//==================================================================
|
||||
// TREE.CPP
|
||||
// Filen innehåller funktioner för trädet
|
||||
// Christian Ohlsson
|
||||
// Karlstad 980927
|
||||
//==================================================================
|
||||
|
||||
#include "header.hpp"
|
||||
|
||||
//##################################################################
|
||||
// SKAPAR ETT TRÄD & SÄTTER NODE TILL NULL
|
||||
//==================================================================
|
||||
treeClass::treeClass():node(NULL)
|
||||
{
|
||||
}
|
||||
//##################################################################
|
||||
// DESTROYTREE
|
||||
// traverserar genom trädet rekursivt
|
||||
// och raderar hela trädet
|
||||
// pre: att det finns ett träd
|
||||
// post: samtliga noder i trädet är borttagna
|
||||
// calls: destroyTree (rekursivt)
|
||||
//==================================================================
|
||||
void treeClass::destroyTree(ptrType &node)
|
||||
{
|
||||
if(node->left != NULL)
|
||||
destroyTree(node->left);
|
||||
if(node->right != NULL)
|
||||
destroyTree(node->right);
|
||||
delete node;
|
||||
node = NULL;
|
||||
}
|
||||
//##################################################################
|
||||
// SKAPAR EN NOD
|
||||
// pre: TRUE
|
||||
// post: en ny nod har skapats
|
||||
//==================================================================
|
||||
treeNode::treeNode(nameType oneName,numberType oneNumber,
|
||||
ptrType L, ptrType R, int H) : left(L),right(R),height(H)
|
||||
{
|
||||
strcpy(name, oneName);
|
||||
strcpy(number,oneNumber);
|
||||
}
|
||||
//##################################################################
|
||||
// SÖKER EFTER ETT ELEMENT I TRÄDET
|
||||
// pre: att trädet inte är tomt
|
||||
// post: NULL om noden inte fanns
|
||||
// post: sökta noden om den fanns med
|
||||
// calls: seek (rekursivt)
|
||||
//==================================================================
|
||||
ptrType treeClass::seek(ptrType node, nameType oneName)
|
||||
{
|
||||
ptrType treeNodeFound;
|
||||
if(node == NULL)
|
||||
treeNodeFound = NULL;
|
||||
else if (strcmp(node->name, oneName) == 0)
|
||||
treeNodeFound = node;
|
||||
else if (strcmp(node->name, oneName) > 0)
|
||||
treeNodeFound = seek(node->left, oneName);
|
||||
else
|
||||
treeNodeFound = seek(node->right, oneName);
|
||||
return treeNodeFound;
|
||||
}
|
||||
//##################################################################
|
||||
// KOLLAR OM DET FINNS NODER I TRÄDET
|
||||
// pre: TRUE
|
||||
// post: TRUE om trädet är tomt
|
||||
// post: FALSE om det finns noder i trädet
|
||||
//==================================================================
|
||||
bool treeClass::isEmpty()
|
||||
{
|
||||
if (node==NULL)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
//##################################################################
|
||||
// SKRIVER UT TRÄDET I INORDER
|
||||
// pre: att trädet inte är tomt
|
||||
// post: trädet har skrivits ut i bokstavsordning
|
||||
// calls: inOrder (rekursivt)
|
||||
//==================================================================
|
||||
void treeClass::inOrder(ptrType treeNode)
|
||||
{
|
||||
if(treeNode) {
|
||||
inOrder(treeNode->left);
|
||||
cout << setw(NAMESIZE)
|
||||
<< treeNode->name
|
||||
<< setw(NAMESIZE)
|
||||
<< treeNode->number
|
||||
<< setw(NAMESIZE)
|
||||
<< treeNode->height << endl;
|
||||
inOrder(treeNode->right);
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
// SÄTTER IN EN NOD I TRÄDET
|
||||
// pre: att personen inte redan finns
|
||||
// post: trädet har fått en ny nod insatt
|
||||
// på rätt plats.
|
||||
// calls: insert (rekursivt)
|
||||
//==================================================================
|
||||
void treeClass::insert(ptrType &node,nameType oneName,numberType number, int height)
|
||||
{
|
||||
if(node==NULL)
|
||||
node=new treeNode(oneName,number,NULL,NULL,height);
|
||||
else if(strcmp(oneName, node->name) < 0)
|
||||
insert(node->left,oneName,number,height);
|
||||
else
|
||||
insert(node->right,oneName,number,height);
|
||||
}
|
||||
//##################################################################
|
||||
// SÖKER SIG FRAM TILL NODEN SOM SKALL TAS BORT
|
||||
// pre: att det finns ett träd
|
||||
// pre: att noden finns
|
||||
// post: noden har hittats
|
||||
// calls: delRoot, del (rekursivt)
|
||||
//==================================================================
|
||||
void treeClass::del(ptrType &node, nameType oneName)
|
||||
{
|
||||
if(strcmp(oneName,node->name) == 0)
|
||||
delRoot(node);
|
||||
else if(strcmp(oneName,node->name) < 0)
|
||||
del(node->left, oneName);
|
||||
else
|
||||
del(node->right,oneName);
|
||||
}
|
||||
//##################################################################
|
||||
// TAR BORT EN NODEN OM DEN INT HAR TVÅ BARN
|
||||
// pre: att det finns ett träd
|
||||
// pre: att noden finns
|
||||
// post: noden har tagits ur trädet och
|
||||
// de andra noderna sitter nu rätt placerade
|
||||
// calls: delLeft
|
||||
//==================================================================
|
||||
void treeClass::delRoot(ptrType &node)
|
||||
{
|
||||
ptrType delPtr;
|
||||
nameType nyItem;
|
||||
numberType nyNumber;
|
||||
|
||||
if(node != NULL) {
|
||||
if((node->left == NULL) && (node->right == NULL)) {
|
||||
delete node;
|
||||
node = NULL;
|
||||
}
|
||||
else if(node->left == NULL) {
|
||||
delPtr = node;
|
||||
node = node->right;
|
||||
delPtr->right = NULL;
|
||||
delete delPtr;
|
||||
}
|
||||
else if(node->right == NULL) {
|
||||
delPtr = node;
|
||||
node = node->left;
|
||||
delPtr->left = NULL;
|
||||
delete delPtr;
|
||||
}
|
||||
else {
|
||||
delLeft(node->right, nyItem, nyNumber);
|
||||
strcpy(node->name, nyItem);
|
||||
strcpy(node->number, nyNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
// TAR BORT EN NOD TILL VÄNSTER
|
||||
// pre: att det finns ett träd
|
||||
// pre: att noden finns
|
||||
// post: noden har tagits ur trädet och
|
||||
// de andra noderna sitter nu rätt placerade
|
||||
// calls: delLeft (rekursivt)
|
||||
//==================================================================
|
||||
void treeClass::delLeft(ptrType &node, nameType oneName, numberType oneNumber)
|
||||
{
|
||||
if((node != NULL) && (node->left == NULL)) {
|
||||
strcpy(oneName, node->name);
|
||||
strcpy(oneNumber, node->number);
|
||||
ptrType delPtr = node;
|
||||
node = node->right;
|
||||
delPtr->right = NULL;
|
||||
delete delPtr;
|
||||
}
|
||||
else
|
||||
delLeft(node->left, oneName, oneNumber);
|
||||
}
|
||||
//##################################################################
|
||||
// ROTATI0N
|
||||
// roterar trädet så att det blir ett AVL träd
|
||||
// pre: att det finns ett träd
|
||||
// post: trädets alla noder sitter balanserade
|
||||
// calls: rotation (rekursivt), balance,
|
||||
// singleLeft, singleRight, doubleRL, doubleLR
|
||||
//==================================================================
|
||||
void treeClass::rotation(ptrType &node)
|
||||
{
|
||||
if(node) {
|
||||
rotation(node->left);
|
||||
rotation(node->right);
|
||||
if(balance(node) == 2) {
|
||||
if(balance(node->right) >= 1)
|
||||
singleLeft(node);
|
||||
else if(balance(node->right) <= -1)
|
||||
doubleRL(node);
|
||||
}
|
||||
else if(balance(node) == -2) {
|
||||
if(balance(node->left) >= 1)
|
||||
doubleLR(node);
|
||||
else if(balance(node->left) <= -1)
|
||||
singleRight(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
// BALANSERAR TRÄDET
|
||||
// returnerar högerbarnets höjd minus vänsterbarnets
|
||||
// pre: att trädet inte är tomt
|
||||
// post: höjddifferansen är returnerad
|
||||
// calls: none
|
||||
//==================================================================
|
||||
int treeClass::balance(ptrType &node) //eg root
|
||||
{
|
||||
int leftValue, rightValue;
|
||||
if(node->left == NULL)
|
||||
leftValue = -1;
|
||||
else
|
||||
leftValue = node->left->height;
|
||||
if(node->right == NULL)
|
||||
rightValue = -1;
|
||||
else
|
||||
rightValue = node->right->height;
|
||||
return (rightValue - leftValue);
|
||||
}
|
||||
//##################################################################
|
||||
// SINGLE LEFT ROTATION
|
||||
// roterar åt vänster
|
||||
// pre: att det finns ett träd
|
||||
// post: trädet är vänsterroterat
|
||||
// calls: none
|
||||
//==================================================================
|
||||
void treeClass::singleLeft(ptrType &node)
|
||||
{
|
||||
ptrType oldNode = node;
|
||||
node = node->right;
|
||||
oldNode->right = node->left;
|
||||
node->left = oldNode;
|
||||
}
|
||||
//##################################################################
|
||||
// SINGLE RIGHT ROTATION
|
||||
// roterar åt höger
|
||||
// pre: att det finns ett träd
|
||||
// post: trädet är högerroterat
|
||||
// calls: none
|
||||
//==================================================================
|
||||
void treeClass::singleRight(ptrType &node)
|
||||
{
|
||||
ptrType oldNode = node;
|
||||
node = node->left;
|
||||
oldNode->left = node->right;
|
||||
node->right = oldNode;
|
||||
}
|
||||
//##################################################################
|
||||
// DOUBLE RIGHT-LEFT ROTATION
|
||||
// Utför en dubbel höger-vänster rotation
|
||||
// pre: att det finns ett träd
|
||||
// post: trädet är höger-vänster roterat
|
||||
// calls: singleRight, singleLeft
|
||||
//==================================================================
|
||||
void treeClass::doubleRL(ptrType &node)
|
||||
{
|
||||
singleRight(node->right);
|
||||
singleLeft(node);
|
||||
}
|
||||
//##################################################################
|
||||
// DOUBLE LEFT-RIGHT ROTATION
|
||||
// Utför en dubbel vänster-höger rotation
|
||||
// pre: att det finns ett träd
|
||||
// post: trädet är vänster-höger roterat
|
||||
// calls: singleLeft, singleRight
|
||||
//==================================================================
|
||||
void treeClass::doubleLR(ptrType &node)
|
||||
{
|
||||
singleLeft(node->left);
|
||||
singleRight(node);
|
||||
}
|
||||
//##################################################################
|
||||
// SÄTTER ALLA HÖJDER I TRÄDET I POSTORDER
|
||||
// pre: att trädet inte är tomt
|
||||
// post: noderna i trädet har alla rätt höjd
|
||||
// calls: setHeight (rekursivt), maxHeight
|
||||
//==================================================================
|
||||
void treeClass::setHeight(ptrType &node)
|
||||
{
|
||||
if(node) {
|
||||
setHeight(node->left);
|
||||
setHeight(node->right);
|
||||
node->height = maxHeight(node) +1;
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
// FINNER MAXIMAL HÖJD EN NOD BEFINNER SIG PÅ
|
||||
// pre: att trädet inte är tomt
|
||||
// post: maxhöjden har returnerats
|
||||
// calls: inget
|
||||
//==================================================================
|
||||
int treeClass::maxHeight(ptrType &node)
|
||||
{
|
||||
int max;
|
||||
if(node->left && node->right) {
|
||||
max = node->left->height;
|
||||
if(node->right->height > max)
|
||||
return (node->right->height);
|
||||
else
|
||||
return max;
|
||||
}
|
||||
else if(node->left)
|
||||
return (node->left->height);
|
||||
else if(node->right)
|
||||
return (node->right->height);
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
//##################################################################
|
||||
// SPARAR TRÄDET PÅ FIL
|
||||
// läser av nodens namn och nummer i alla noder i
|
||||
// preorder och skriver de på filen.
|
||||
// pre: att det finns ett träd
|
||||
// post: trädet har sparats på fil
|
||||
// calls: save (rekursivt)
|
||||
//==================================================================
|
||||
void treeClass::save(ptrType node, fstream &fil)
|
||||
{
|
||||
if(node) {
|
||||
fil.write((char*)&node->name,sizeof(node->name));
|
||||
fil.write((char*)&node->number,sizeof(node->number));
|
||||
save(node->left,fil);
|
||||
save(node->right,fil);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
Dijkstra/NeverNeverLand.doc
Normal file
BIN
Dijkstra/NeverNeverLand.doc
Normal file
Binary file not shown.
BIN
Dijkstra/dijkstra.exe
Normal file
BIN
Dijkstra/dijkstra.exe
Normal file
Binary file not shown.
285
Dijkstra/graf.cpp
Normal file
285
Dijkstra/graf.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
/************************************************
|
||||
* Laboration 4 i
|
||||
* Datastrukturer och Algoritmer
|
||||
* Dijkstras Shortest Path
|
||||
*************************************************
|
||||
* Christian Ohlsson
|
||||
* Karlstads universitet, 1999
|
||||
*
|
||||
* graf.cpp
|
||||
* Innehåller de funktioner programmet
|
||||
* använder sig av för att beräkna
|
||||
* den kortaste vägen
|
||||
*************************************************/
|
||||
|
||||
#include "header.h"
|
||||
/*===============================================
|
||||
* graphNode
|
||||
* Construktor.
|
||||
* Skapar en graphNode
|
||||
-------------------------------------------------*/
|
||||
graphNode::graphNode() {
|
||||
startCity = -1;
|
||||
endCity = -1;
|
||||
Start = 0;
|
||||
End = 0;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* Operator ==
|
||||
* Operatoröverlagring
|
||||
-------------------------------------------------*/
|
||||
|
||||
int graphNode::operator==(graphNode node) {
|
||||
if(Start != node.Start || End != node.End ||
|
||||
startCity != node.startCity || endCity != node.endCity)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* Operator =
|
||||
* Operatoröverlagring
|
||||
-------------------------------------------------*/
|
||||
void graphNode::operator=(graphNode node) {
|
||||
startCity = node.startCity;
|
||||
endCity = node.endCity;
|
||||
Start = node.Start;
|
||||
End = node.End;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* Operator >
|
||||
* Operatoröverlagring
|
||||
-------------------------------------------------*/
|
||||
int graphNode::operator>(graphNode node) {
|
||||
if(Start <= node.Start)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* dijkstraNode
|
||||
* Construktor.
|
||||
* Skapar en Dijkstra node
|
||||
-------------------------------------------------*/
|
||||
dijkstraNode::dijkstraNode() {
|
||||
deleted = false;
|
||||
lastCity = 0;
|
||||
Totaltime = MAXINT; //Tiden sätts till max
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* ~dijkstraNode
|
||||
* Destruktor.
|
||||
* Tar bort en nod
|
||||
-------------------------------------------------*/
|
||||
dijkstraNode::~dijkstraNode() {}
|
||||
|
||||
/*===============================================
|
||||
* graph
|
||||
* Construktor
|
||||
* Skapar en graph
|
||||
-------------------------------------------------*/
|
||||
graph::graph() {
|
||||
visitedCities = 0;
|
||||
table = NULL;
|
||||
lastPath = NULL;
|
||||
prevSize = 0;
|
||||
lastTime = 0;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* ~graph
|
||||
* Destruktor
|
||||
* Anropar deleteGraph
|
||||
-------------------------------------------------*/
|
||||
graph::~graph() { deleteGraph(); }
|
||||
|
||||
/*===============================================
|
||||
* deleteGraph
|
||||
* Tömmer grafen på info
|
||||
-------------------------------------------------*/
|
||||
void graph::deleteGraph() {
|
||||
if(table != NULL)
|
||||
delete[] table;
|
||||
if(lastPath != NULL)
|
||||
delete[] lastPath;
|
||||
table = NULL;
|
||||
lastPath = NULL;
|
||||
visitedCities = 0;
|
||||
prevSize = 0;
|
||||
lastTime = 0;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* makeGraph
|
||||
* Skapar en graf med size stycken städer.
|
||||
* Tar först bort eventuell gammal graf.
|
||||
* Returnerar true om allt gick bra
|
||||
-------------------------------------------------*/
|
||||
int graph::makeGraph(int size) {
|
||||
deleteGraph();
|
||||
table = new list<graphNode>*[size];
|
||||
if(table == NULL)
|
||||
return false;
|
||||
for(int index = 0; index < size; index++)
|
||||
table[index] = new list<graphNode>[size];
|
||||
if(table == NULL)
|
||||
return false;
|
||||
visitedCities = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* connect
|
||||
* Skapar förbindelse mellan noderna i grafen
|
||||
-------------------------------------------------*/
|
||||
void graph::connect(int startvertex, int endvertex, graphNode node) {
|
||||
if(startvertex < 0 || startvertex > visitedCities-1 ||
|
||||
endvertex < 0 || endvertex > visitedCities-1)
|
||||
return;
|
||||
node.startCity = startvertex;
|
||||
node.endCity = endvertex;
|
||||
table[startvertex][endvertex].insert(node);
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* shortestPath
|
||||
* Letar reda på den kortaste
|
||||
* vägen mellan två noder
|
||||
-------------------------------------------------*/
|
||||
graphNode graph::shortestPath(int startvertex, int endvertex, int time) {
|
||||
int index, time1, time2;
|
||||
graphNode node1, node2;
|
||||
if(startvertex < 0 || startvertex > visitedCities-1 ||
|
||||
endvertex < 0 || endvertex > visitedCities-1)
|
||||
return node1;
|
||||
int connections = table[startvertex][endvertex].listLength();
|
||||
if(connections == 0) return node1;
|
||||
node1 = table[startvertex][endvertex].printElement(1);
|
||||
time1 = getTime(node1, time);
|
||||
for(index = 2; index <= connections; index++) {
|
||||
node2 = table[startvertex][endvertex].printElement(index);
|
||||
time2 = getTime(node2, time);
|
||||
if(time1 > time2) {
|
||||
node1 = node2;
|
||||
time1 = time2;
|
||||
}
|
||||
}
|
||||
return node1;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* getTime
|
||||
* Returnerar antalet timmar mellan tiden
|
||||
* time och tiden som finns i noden
|
||||
-------------------------------------------------*/
|
||||
int graph::getTime(graphNode node, int time) {
|
||||
int total;
|
||||
if(node.Start >= time && node.End > time && node.Start < node.End)
|
||||
total = node.End - time;
|
||||
else if(node.Start > node.End)
|
||||
total = ( (24 - time + node.Start) + (24 - node.Start + node.End) );
|
||||
else
|
||||
total = (24 - time + node.End);
|
||||
return total;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* dijkstra
|
||||
* Beräknar den kortaste sträckan dvs. tiden
|
||||
* mellan två städer i NeverNeverLand
|
||||
-------------------------------------------------*/
|
||||
void graph::dijkstra(int startvertex, int endvertex, int time) {
|
||||
delPath();
|
||||
if(startvertex == endvertex || startvertex < 0 ||
|
||||
startvertex > visitedCities-1 || endvertex < 0 ||
|
||||
endvertex > visitedCities-1)
|
||||
return;
|
||||
|
||||
dijkstraNode *temparray = new dijkstraNode[visitedCities];
|
||||
if(temparray == NULL) return;
|
||||
int min, index, parent = 0, temptime;
|
||||
graphNode tempnode;
|
||||
temparray[startvertex].Totaltime = 0;
|
||||
temparray[startvertex].deleted = true;
|
||||
min = startvertex;
|
||||
while(min != endvertex) {
|
||||
for(index = 0; index < visitedCities; index++) {
|
||||
if(!temparray[index].deleted) {
|
||||
tempnode = shortestPath(min, index, time);
|
||||
if(tempnode.startCity != -1) {
|
||||
temptime = getTime(tempnode, time);
|
||||
if((temptime + temparray[min].Totaltime)
|
||||
< temparray[index].Totaltime) {
|
||||
temparray[index].Totaltime =
|
||||
temptime + temparray[min].Totaltime;
|
||||
if(parent == 0)
|
||||
temparray[index].lastCity = 0;
|
||||
else
|
||||
temparray[index].lastCity = min;
|
||||
temparray[index].Node = tempnode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
min = getMinTime(temparray);
|
||||
temparray[min].deleted = true;
|
||||
time = temparray[min].Node.End;
|
||||
parent++;
|
||||
}
|
||||
calcPath(temparray, min);
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* calcPath
|
||||
* Skapar en array med information
|
||||
* om den kortaste vägen.
|
||||
-------------------------------------------------*/
|
||||
void graph::calcPath(dijkstraNode *array, int start) {
|
||||
graphNode *path = new graphNode[visitedCities];
|
||||
if(path == NULL)
|
||||
return;
|
||||
int temp = 1, index = start;
|
||||
while(array[index].lastCity > 0) {
|
||||
temp++;
|
||||
index = array[index].lastCity;
|
||||
}
|
||||
prevSize = temp;
|
||||
lastTime = array[start].Totaltime;
|
||||
for(index = temp-1; index >= 0; index--) {
|
||||
path[index] = array[start].Node;
|
||||
start = array[start].lastCity;
|
||||
}
|
||||
lastPath = path;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* getMinIndex
|
||||
* Hittar den minsta noden i en array och
|
||||
* returnerar dess index i arrayen
|
||||
-------------------------------------------------*/
|
||||
int graph::getMinTime(dijkstraNode *temptable) {
|
||||
int temp = 0, index;
|
||||
while(temptable[temp].deleted)
|
||||
temp++;
|
||||
for(index = temp+1; index < visitedCities; index++) {
|
||||
if(!temptable[index].deleted) {
|
||||
if(temptable[temp].Totaltime > temptable[index].Totaltime)
|
||||
temp = index;
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* delPath
|
||||
* Tar bort det som lastpath pekar på
|
||||
-------------------------------------------------*/
|
||||
void graph::delPath() {
|
||||
if(lastPath != NULL)
|
||||
delete[] lastPath;
|
||||
lastPath = NULL;
|
||||
prevSize = 0;
|
||||
}
|
||||
75
Dijkstra/graf.h
Normal file
75
Dijkstra/graf.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/************************************************
|
||||
* Laboration 4 i
|
||||
* Datastrukturer och Algoritmer
|
||||
* Dijkstras Shortest Path
|
||||
*************************************************
|
||||
* Christian Ohlsson
|
||||
* Karlstads universitet, 1999
|
||||
*
|
||||
* Graph.h
|
||||
* Innehåller de definitioner och klasser
|
||||
* som används för att beräkna kortaste
|
||||
* vägen mellan två städer
|
||||
*************************************************/
|
||||
|
||||
#ifndef _GRAPH_H_
|
||||
#define _GRAPH_H_
|
||||
#include "list.h"
|
||||
|
||||
/*===============================================
|
||||
* graphNode
|
||||
* Nod mellan två städer
|
||||
-------------------------------------------------*/
|
||||
class graphNode {
|
||||
public:
|
||||
graphNode(); //Construktor
|
||||
~graphNode() {}; //Destruktor
|
||||
int startCity; //Stad man åker ifrån
|
||||
int endCity; //Stad man kommer till
|
||||
int Start; //Starttid
|
||||
int End; //Ankomsttid
|
||||
void operator=(graphNode node); //Operator-överlagring
|
||||
int operator>(graphNode node); //för noder
|
||||
int operator==(graphNode node); //...
|
||||
};
|
||||
|
||||
/*===============================================
|
||||
* dijkstraNode
|
||||
* Speciell nod för Dijkstra
|
||||
-------------------------------------------------*/
|
||||
class dijkstraNode {
|
||||
public:
|
||||
int deleted; //Märkning för noden
|
||||
int lastCity; //Föregående besökt stad
|
||||
int Totaltime; //TotaL restid
|
||||
dijkstraNode(); //Construktor
|
||||
~dijkstraNode(); //Destruktor
|
||||
graphNode Node; //En nod
|
||||
};
|
||||
|
||||
/*===============================================
|
||||
* graph
|
||||
* Skapar en graf och sköter uträkningen
|
||||
-------------------------------------------------*/
|
||||
class graph {
|
||||
private:
|
||||
int visitedCities; //Antalet traverserade städer
|
||||
list<graphNode> **table; //Resväg
|
||||
graphNode shortestPath(int startvertex, int endvertex, int time);
|
||||
void delPath();
|
||||
int getTime(graphNode node, int time);
|
||||
int getMinTime(dijkstraNode *temptable);
|
||||
void calcPath(dijkstraNode *array, int start);
|
||||
public:
|
||||
int lastTime; //Tid som ökas när vi reser
|
||||
int prevSize; //Antalet städer i arrayen
|
||||
graphNode *lastPath; //Traverserad väg
|
||||
graph(); //Construktor
|
||||
~graph(); //Destruktor
|
||||
void deleteGraph();
|
||||
void connect(int startvertex, int endvertex, graphNode node);
|
||||
int makeGraph(int size);
|
||||
void dijkstra(int startvertex, int endvertex, int time);
|
||||
};
|
||||
#endif
|
||||
|
||||
36
Dijkstra/header.h
Normal file
36
Dijkstra/header.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/************************************************
|
||||
* Laboration 4 i
|
||||
* Datastrukturer och Algoritmer
|
||||
* Dijkstras Shortest Path
|
||||
*************************************************
|
||||
* Christian Ohlsson
|
||||
* Karlstads universitet, 1999
|
||||
*
|
||||
* Header.h
|
||||
* Innehåller definitioner och includes
|
||||
* som används i programmet.
|
||||
*************************************************/
|
||||
|
||||
#ifndef ___HEADER___
|
||||
#define ___HEADER___
|
||||
|
||||
#include <iostream.h>
|
||||
#include <stdlib.h>
|
||||
#include <values.h>
|
||||
#include <fstream.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
|
||||
#include "graf.h"
|
||||
#include "list.h"
|
||||
|
||||
const int false=0; //boolsk variabel
|
||||
const int true=!false; //boolsk variabel
|
||||
const int citySize=25; //Max antal tecken i en stad
|
||||
const int numOfCities=13; //Antalet städer
|
||||
const int FORWARD=2; //För inläsning
|
||||
const int MAXTIME = 6; //Max antal tkn
|
||||
const int BASE=10; //Talbas
|
||||
const int BUFFERSIZE=20; //Buffer för säker inmatning
|
||||
|
||||
#endif
|
||||
240
Dijkstra/list.h
Normal file
240
Dijkstra/list.h
Normal file
@@ -0,0 +1,240 @@
|
||||
/************************************************
|
||||
* Laboration 4 i
|
||||
* Datastrukturer och Algoritmer
|
||||
* Dijkstras Shortest Path
|
||||
*************************************************
|
||||
* Christian Ohlsson
|
||||
* Karlstads universitet, 1999
|
||||
*
|
||||
* list.h
|
||||
* Innehåller definitioner och funktioner
|
||||
* för en templatelista.
|
||||
*************************************************/
|
||||
|
||||
#ifndef _LISTA_H_
|
||||
#define _LISTA_H_
|
||||
|
||||
#include "header.h"
|
||||
|
||||
/*===============================================
|
||||
* list
|
||||
* Denna klass skapar en templatelista.
|
||||
* Varje nod innehåller ett godtyckligt data-
|
||||
* fält och en pekare till nästa nod.
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
class list {
|
||||
private:
|
||||
struct nod { // En template nod
|
||||
T data;
|
||||
nod *next;
|
||||
};
|
||||
int size; // Storleken på listan.
|
||||
nod *head; // Pekar på första elementet i listan.
|
||||
public:
|
||||
list();
|
||||
~list();
|
||||
int listLength(); //Storleken på listan
|
||||
void insert(T data); //Sätter in en nod
|
||||
void del(int place); //Tar bort en nod
|
||||
void sort(void); //Sorterar listan
|
||||
int seek(T data); //Söker i listan
|
||||
int isFree(void); //Kollar om det finns element i listan
|
||||
void delAll(void); //Tar bort allt i listan
|
||||
int occupiedExist(T data); //Kollar om inmatat värde existerar
|
||||
int occupied(int place); //Testar om det finns plats
|
||||
void setNode(nod *dat, T data); //Mata in data i den nya noden
|
||||
T printElement(int place); //Visar Innehållet på bestämd plats.
|
||||
T *getPtr(int place); //Returnera platsen på place position
|
||||
};
|
||||
|
||||
|
||||
/*===============================================
|
||||
* list
|
||||
* Construktor, skapar en lista
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
list<T>::list() {
|
||||
head = NULL;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* ~list
|
||||
* Destruktor. Anropar delAll
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
list<T>::~list() { delAll(); }
|
||||
|
||||
/*===============================================
|
||||
* insert
|
||||
* Sätter in en ny nod i listan
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
void list<T>::insert(T data) {
|
||||
nod *newNode = new nod;
|
||||
newNode->next = head;
|
||||
head = newNode;
|
||||
size++;
|
||||
newNode->data = data;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* del
|
||||
* Tar bort ett element på en viss
|
||||
* position i listan
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
void list<T>::del(int place) {
|
||||
int i = 1;
|
||||
nod *temp1;
|
||||
temp1 = head;
|
||||
nod *temp2;
|
||||
temp2 = head->next;
|
||||
if(temp2 == NULL || place == 1) { //Bara ett element i listan
|
||||
head = temp1->next;
|
||||
delete temp1;
|
||||
size--;
|
||||
}
|
||||
else { //Flera element i listan
|
||||
temp2 = head;
|
||||
while(i < place) {
|
||||
temp1 = temp2;
|
||||
temp2 = temp1->next;
|
||||
i++;
|
||||
}
|
||||
temp1->next = temp2->next;
|
||||
delete temp2;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* isFree
|
||||
* Kollar om listan är tom. Returnerar
|
||||
* true om listan är tom
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
int list<T>::isFree() {
|
||||
if(size == 0) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* occupied
|
||||
* Kollar om plats finns på en angiven
|
||||
* position.
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
int list<T>::occupied(int place) {
|
||||
if( (place < 1) || (place > size) ) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* listLength
|
||||
* Returnerar antalet element i listan
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
int list<T>::listLength() { return size; }
|
||||
|
||||
/*===============================================
|
||||
* sort
|
||||
* Sorterar elementen i listan
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
void list<T>::sort() {
|
||||
nod *temp;
|
||||
T sop;
|
||||
int changed;
|
||||
do {
|
||||
changed = 0;
|
||||
for(temp = head; temp != NULL; temp = temp->next)
|
||||
if(temp->data > temp->next->data) {
|
||||
sop = temp->data;
|
||||
temp->data = temp->next->data;
|
||||
temp->next->data = sop;
|
||||
changed = 1;
|
||||
}
|
||||
}while(changed);
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* delAll
|
||||
* Tar bort alla element i listan.
|
||||
* Sätter sedan storleken till 0
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
void list<T>::delAll() {
|
||||
nod *temp1 = head;
|
||||
nod *temp2;
|
||||
head = NULL;
|
||||
while(temp1 != NULL) {
|
||||
temp2 = temp1;
|
||||
temp1 = temp1->next;
|
||||
delete temp2;
|
||||
}
|
||||
size = 0;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
*
|
||||
*
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
int list<T>::occupiedExist(T data) { //Kollar om inmatat värde existerar
|
||||
nod *temp;
|
||||
for(temp = head; temp != NULL; temp = temp->next)
|
||||
if(temp->data == data)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
*
|
||||
*
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
int list<T>::seek(T data) { //Söker efter ett element i listan
|
||||
nod *temp;
|
||||
int position = 0;
|
||||
for(temp = head; temp != NULL; temp = temp->next) {
|
||||
position++;
|
||||
if(temp->data == data)
|
||||
return position; //Funnet! Returnera positionen
|
||||
}
|
||||
position = 0;
|
||||
return position; //Inget hittades, returnera 0
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* printElement
|
||||
* Hämtar element på en angiven plats
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
T list<T>::printElement(int place) {
|
||||
nod *temp1 = head;
|
||||
int i = 1;
|
||||
while(i < place && i < size) {
|
||||
temp1 = temp1->next;
|
||||
i++;
|
||||
}
|
||||
return temp1->data;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* getPtr
|
||||
* Returnera adressen till ett element
|
||||
* på en angiven plats
|
||||
-------------------------------------------------*/
|
||||
template <class T>
|
||||
T *list<T>::getPtr(int place) {
|
||||
nod *temp1 = head;
|
||||
int i = 1;
|
||||
while(i < place && i < size) {
|
||||
temp1 = temp1->next;
|
||||
i++;
|
||||
}
|
||||
return &(temp1->data);
|
||||
}
|
||||
#endif
|
||||
191
Dijkstra/main.cpp
Normal file
191
Dijkstra/main.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/************************************************
|
||||
* Laboration 4 i
|
||||
* Datastrukturer och Algoritmer
|
||||
* Dijkstras Shortest Path
|
||||
*************************************************
|
||||
* Christian Ohlsson
|
||||
* Karlstads universitet, 1999
|
||||
*
|
||||
* main.cpp
|
||||
* Innehåller drivrutiner för
|
||||
* Dijkstra labben.
|
||||
* Skapat med Borland C++ 4.0
|
||||
* Låt main.cpp och graph.cpp
|
||||
* finnas i projektet.
|
||||
* Kompilera för Easywin, Windows 3.x
|
||||
* 16-bitar, target: Small
|
||||
* Se till att filen network.txt finns
|
||||
* i samma katalog som dijkstra.exe
|
||||
*************************************************/
|
||||
|
||||
#include "header.h"
|
||||
|
||||
/*===============================================
|
||||
* cities
|
||||
* Alla städer i NeverNeverLand
|
||||
-------------------------------------------------*/
|
||||
const char cities[numOfCities][citySize] = {
|
||||
{"Wonderland"},
|
||||
{"Sanctuary"},
|
||||
{"Battlefield"},
|
||||
{"Octopus's Garden"},
|
||||
{"Paradise City"},
|
||||
{"Strawberry Fields"},
|
||||
{"Chaos"},
|
||||
{"El Dorado"},
|
||||
{"Kozmic Place"},
|
||||
{"Oz"},
|
||||
{"Nowhereland"},
|
||||
{"Shangrila"},
|
||||
{"Southbound"}
|
||||
};
|
||||
|
||||
graph myGraph; //Global klass för grafen
|
||||
|
||||
/*===============================================
|
||||
* mataIn
|
||||
* Ser till att bara tal matas in
|
||||
-------------------------------------------------*/
|
||||
int mataIn() {
|
||||
char buffer[BUFFERSIZE];
|
||||
int f;
|
||||
do {
|
||||
cin >> buffer;
|
||||
if (strcmp(buffer,"0") == 0) return 0;
|
||||
else {
|
||||
f = atoi(buffer);
|
||||
if (f!=0) return f;
|
||||
else cout <<"NAN, try again: ";
|
||||
}
|
||||
}while (!f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* getName
|
||||
* Hämtar namn på stad, dvs det nummer staden
|
||||
* motsvarar
|
||||
-------------------------------------------------*/
|
||||
int getName(char *text) {
|
||||
int i = 0;
|
||||
while(strcmp(text, cities[i]) !=0 && i < numOfCities)
|
||||
i++;
|
||||
if(i >= numOfCities) return -1;
|
||||
else return i;
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* readGraph
|
||||
* Läser in alla städer och tider från fil.
|
||||
-------------------------------------------------*/
|
||||
void readGraph()
|
||||
{
|
||||
graphNode node;
|
||||
ifstream myFile;
|
||||
char temp[citySize];
|
||||
if(!myGraph.makeGraph(numOfCities)) { //Skapar en graf
|
||||
cout<<"Could not make graph";getch();
|
||||
return;
|
||||
}
|
||||
myFile.open("network.txt"); //Öppnar filen
|
||||
do {
|
||||
myFile.get(temp, citySize);
|
||||
node.startCity = getName(temp); //Hämtar startstad
|
||||
myFile.seekg(FORWARD, ios::cur);
|
||||
myFile.get(temp, citySize);
|
||||
node.endCity = getName(temp); //Hämtar slutstad
|
||||
myFile.seekg(FORWARD, ios::cur);
|
||||
myFile.get(temp, citySize);
|
||||
node.Start = atoi(temp); //Hämtar starttid
|
||||
myFile.seekg(FORWARD, ios::cur);
|
||||
myFile.get(temp, citySize);
|
||||
node.End = atoi(temp); //Hämtar sluttid
|
||||
myFile.seekg(FORWARD, ios::cur);
|
||||
myGraph.connect(node.startCity, node.endCity, node); //Sätter in noden
|
||||
} while(myFile.peek() != EOF);
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* printPath
|
||||
* Skriver ut kortaste vägen
|
||||
-------------------------------------------------*/
|
||||
void printPath() {
|
||||
int index;
|
||||
char text[citySize * 4], time[MAXTIME];
|
||||
cout << "The shortest path is:"
|
||||
<< "\n________________________________________________________";
|
||||
for(index = 0; index < myGraph.prevSize; index++) {
|
||||
text[0] = 0;
|
||||
time[0] = 0;
|
||||
cout << "\nFrom " << cities[myGraph.lastPath[index].startCity];
|
||||
itoa(myGraph.lastPath[index].Start, time, BASE);
|
||||
cout << " "<< time << ":00\t";
|
||||
time[0] = 0;
|
||||
|
||||
cout << "to ";
|
||||
cout << cities[myGraph.lastPath[index].endCity];
|
||||
itoa(myGraph.lastPath[index].End, time, BASE);
|
||||
cout << " " << time << ":00\t";
|
||||
}
|
||||
text[0] = 0; time[0] = 0;
|
||||
itoa(myGraph.lastTime, time, BASE);
|
||||
cout << "\n________________________________________________________";
|
||||
cout << "\nThe total travelling time is "<<time<<" hours";
|
||||
}
|
||||
/*===============================================
|
||||
* printTowns
|
||||
* Skriver ut alla städer på skärmen
|
||||
-------------------------------------------------*/
|
||||
void printTowns()
|
||||
{
|
||||
clrscr();
|
||||
cout << "\t\t\t\t\t\t\t\t<b-brox>"
|
||||
<< "\n Welcome to the RailWay Company"
|
||||
<< "\n in the NeverNeverLand..."
|
||||
<< "\n ____________________________________________________"
|
||||
<< "\n | 0. Wonderland 7. El Dorado |"
|
||||
<< "\n | 1. Sanctuary 8. Kozmic Place |"
|
||||
<< "\n | 2. Battlefield 9. Oz |"
|
||||
<< "\n | 3. Octopus's Garden 10. Nowhereland |"
|
||||
<< "\n | 4. Paradise City 11. Shangrila |"
|
||||
<< "\n | 5. Strawberry Fields 12. Southbound |"
|
||||
<< "\n | 6. Chaos |"
|
||||
<< "\n |__________________________________________________|"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
/*===============================================
|
||||
* main
|
||||
* Huvudfunktionen för programmet.
|
||||
* Läser in grafen och ber användaren
|
||||
* mata in mellan vilka städer han skall resa
|
||||
-------------------------------------------------*/
|
||||
void main() {
|
||||
int start, end, time;
|
||||
char playAgain;
|
||||
readGraph(); //Läs in filen
|
||||
do{
|
||||
printTowns(); //Skriv ut städerna
|
||||
do {
|
||||
cout <<"\nFrom wich town (0-"<<(numOfCities-1)<<"): ";
|
||||
start=mataIn();
|
||||
}while(start<0 || start>numOfCities-1);
|
||||
do {
|
||||
cout <<"To wich town (0-"<<(numOfCities-1)<<"): ";
|
||||
end=mataIn();
|
||||
}while(end<0 || end>numOfCities-1);
|
||||
do {
|
||||
cout <<"Time of departure (0-24): ";
|
||||
time=mataIn();
|
||||
}while(time<0 || time>24);
|
||||
myGraph.dijkstra(start, end, time); //Beräkna kortaste väg
|
||||
if(myGraph.prevSize > 0)
|
||||
printPath(); //Skriv ut vägen
|
||||
else
|
||||
cout <<"\nStarttown and arrivaltown are the same! Are you stupid?";
|
||||
cout <<"\n\nPlay Again (Y/N)? ";
|
||||
cin >> playAgain;
|
||||
}while(playAgain == 'y' || playAgain == 'Y');
|
||||
}
|
||||
|
||||
|
||||
BIN
Dijkstra/map.gif
Normal file
BIN
Dijkstra/map.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
1068
Dijkstra/network.txt
Normal file
1068
Dijkstra/network.txt
Normal file
File diff suppressed because it is too large
Load Diff
17
Dijkstra/read_me
Normal file
17
Dijkstra/read_me
Normal file
@@ -0,0 +1,17 @@
|
||||
Laboration 4 i
|
||||
Datastrukturer och Algoritmer
|
||||
Dijkstra's shortest path
|
||||
------------------------------------------------
|
||||
Stort OBS!
|
||||
Denna lab är utvecklad under windows
|
||||
med Borland C++ 5.0
|
||||
Kompilering under Linux kommer ej
|
||||
att fungera utan lite trix.
|
||||
Tex finns inte funktioner som clrscr()
|
||||
i Linux.
|
||||
Exe-filen borde gå att köra på en windows-
|
||||
dator. Se till att network.txt finns i samma
|
||||
katalog som exe-filen.
|
||||
Labben är provkörd och klar.
|
||||
------------------------------------------------
|
||||
Christian Ohlsson, di7chro@cse.kau.se, 1999
|
||||
292
Hashing/hash.cpp
Normal file
292
Hashing/hash.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
//##################################################################
|
||||
// PROGRAMMERINGSUPPGIFT 3
|
||||
// DATASTRUKTURER OCH ALGORITMER
|
||||
// HASH TABELL
|
||||
//==================================================================
|
||||
// HASH.HPP
|
||||
// Filen innehåller hashfunktionerna
|
||||
// Christian Ohlsson
|
||||
// Ingela Johansson
|
||||
// Anna-Maria Haglund
|
||||
// Karlstad 981007
|
||||
//==================================================================
|
||||
|
||||
#include "header.hpp"
|
||||
//##################################################################
|
||||
//Function: hashClass()
|
||||
//Task: constuctorn
|
||||
//Calls: nothing
|
||||
//==================================================================
|
||||
hashClass::hashClass()
|
||||
{
|
||||
prime();
|
||||
PRIMENUMBER=0;
|
||||
ARRAYSIZE = DEFAULTSIZE;
|
||||
hashPtr = new hashNode[ARRAYSIZE];
|
||||
for(int i=0; i<ARRAYSIZE ; i++) {
|
||||
strcpy(hashPtr[i].name, "");
|
||||
strcpy(hashPtr[i].number, "");
|
||||
hashPtr[i].exist = FALSE;
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
//Function: ~hashclass
|
||||
//Task: destructorn
|
||||
//Calls: nothing
|
||||
//==================================================================
|
||||
hashClass::~hashClass(){ delete hashPtr; }
|
||||
//##################################################################
|
||||
//Function: getSize()
|
||||
//Task: returnerar storleken på hashtabellen
|
||||
//Calls: nothing
|
||||
//==================================================================
|
||||
int hashClass::getSize(){ return ARRAYSIZE; }
|
||||
//##################################################################
|
||||
//Function: nextPrime()
|
||||
//Task: returnerar nästa primtal
|
||||
//Calls: nothing
|
||||
//==================================================================
|
||||
int hashClass::nextPrime()
|
||||
{
|
||||
PRIMENUMBER++;
|
||||
return primeArray[DEFAULTPRIMENUMBER+PRIMENUMBER];
|
||||
}
|
||||
//##################################################################
|
||||
//Function: prime()
|
||||
//Task: lägger in primtalen i en array
|
||||
//Calls: isPrime()
|
||||
//==================================================================
|
||||
void hashClass::prime()
|
||||
{
|
||||
int i = 1, num=FIRSTPRIME;
|
||||
primeArray[0] = STARTPRIME;
|
||||
|
||||
while(i<PRIMEARRAYSIZE) {
|
||||
if(isPrime(num, i, primeArray)) {
|
||||
primeArray[i] = num;
|
||||
i++;
|
||||
}
|
||||
num = (num+PRIMESTEP);
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
//Function: isPrime()
|
||||
//Task: kollar om ett tal är ett primtal
|
||||
//Calls: nothing
|
||||
//=================================================================
|
||||
|
||||
bool hashClass::isPrime(int nummer, int antal, int primeArray[PRIMEARRAYSIZE])
|
||||
{
|
||||
for(int i = 0; i < antal; i++)
|
||||
if(nummer%primeArray[i] == 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
//##################################################################
|
||||
//Function: search()
|
||||
//Task: söker efter ett namn i tabellen
|
||||
//Calls: hash1() och hash2()
|
||||
//==================================================================
|
||||
bool hashClass::search(nameType name)
|
||||
{
|
||||
int location = hash1(name);
|
||||
if(strcmp(hashPtr[location].name, name) == 0)
|
||||
return TRUE;
|
||||
else
|
||||
while(hashPtr[location].exist == TRUE) {
|
||||
location = location + hash2(hash1(name));
|
||||
if(location > ARRAYSIZE)
|
||||
location = location - ARRAYSIZE;
|
||||
if(strcmp(hashPtr[location].name, name) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
//##################################################################
|
||||
//Function: getNode()
|
||||
//Task: hämtar en nod ur tabellen, d.v.s. namn telefonnummer och
|
||||
// "deleted-flaggan"
|
||||
//Calls: hash1() och hash2()
|
||||
//==================================================================
|
||||
hashNode hashClass::getNode(nameType &oneName)
|
||||
{
|
||||
int location = hash1(oneName);
|
||||
if(strcmp(hashPtr[location].name, oneName) == 0)
|
||||
return (hashPtr[location]);
|
||||
else
|
||||
do {
|
||||
location = location + hash2(hash1(oneName));
|
||||
if(location>ARRAYSIZE) {
|
||||
location = (location-ARRAYSIZE);
|
||||
if(strcmp(hashPtr[location].name, oneName) == 0)
|
||||
return hashPtr[location];
|
||||
}
|
||||
}while(hashPtr[location].exist == FALSE);
|
||||
}
|
||||
//##################################################################
|
||||
//Function: biggerHash()
|
||||
//Task: kollar om en större tabell behövs (om 80% av positionerna
|
||||
// är upptagna)
|
||||
//Calls: checkOccupied()
|
||||
//==================================================================
|
||||
bool hashClass::biggerHash()
|
||||
{
|
||||
float siz = INSERTFACTOR*getSize();
|
||||
int occ = checkOccupied();
|
||||
if(occ>=siz)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
//##################################################################
|
||||
//Function: newHashArray()
|
||||
//Task:
|
||||
//Calls: reHash()
|
||||
//==================================================================
|
||||
void hashClass::newHashArray()
|
||||
{
|
||||
int oldSize = ARRAYSIZE;
|
||||
ARRAYSIZE = nextPrime();
|
||||
reHash(oldSize);
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
bool hashClass::anotherHash()
|
||||
{
|
||||
int del=0;
|
||||
float siz = DELETEFACTOR*getSize();
|
||||
for(int i=0; i<ARRAYSIZE ; i++)
|
||||
if(hashPtr[i].exist == TRUE && !hashPtr[i].name[0])
|
||||
del++;
|
||||
if(del>=siz)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
void hashClass::reHash(int oldSize)
|
||||
{
|
||||
int location;
|
||||
hashNode *tempPtr = new hashNode[ARRAYSIZE];
|
||||
for(int j=0; j<oldSize ; j++) {
|
||||
strcpy(tempPtr[j].name, hashPtr[j].name);
|
||||
strcpy(tempPtr[j].number, hashPtr[j].number);
|
||||
tempPtr[j].exist = hashPtr[j].exist;
|
||||
}
|
||||
destroyHash(oldSize);
|
||||
hashPtr = new hashNode[ARRAYSIZE];
|
||||
for(int k=0; k<ARRAYSIZE ; k++) {
|
||||
strcpy(hashPtr[k].name, "");
|
||||
strcpy(hashPtr[k].number, "");
|
||||
hashPtr[k].exist = FALSE;
|
||||
}
|
||||
for(int i=0; i<oldSize ; i++)
|
||||
if(tempPtr[i].exist == TRUE && tempPtr[i].name[0]) {
|
||||
location = hash1(tempPtr[i].name);
|
||||
if(hashPtr[location].exist == FALSE)
|
||||
insert(location, tempPtr[i]);
|
||||
else
|
||||
while(hashPtr[location].exist == TRUE) {
|
||||
location = location + hash2(hash1(tempPtr[i].name));
|
||||
if(location > ARRAYSIZE)
|
||||
location = location - ARRAYSIZE;
|
||||
if(hashPtr[location].exist == FALSE)
|
||||
insert(location, tempPtr[i]);
|
||||
}
|
||||
}
|
||||
delete tempPtr;
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
int hashClass::hash1(nameType name)
|
||||
{
|
||||
int sum = 0;
|
||||
for(int i=0 ; i<strlen(name) ; i++)
|
||||
sum = name[i] + sum;
|
||||
return (sum % ARRAYSIZE);
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
int hashClass::hash2(int key){ return(STEPSIZE - (key % STEPSIZE)) }
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
int hashClass::checkOccupied()
|
||||
{
|
||||
int occupied = 0;
|
||||
for(int i=0 ; i<ARRAYSIZE ; i++)
|
||||
if(hashPtr[i].exist == TRUE)
|
||||
occupied++;
|
||||
return occupied;
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
void hashClass::destroyHash(int oldSize)
|
||||
{
|
||||
for(int i = 0; i < oldSize; i++)
|
||||
delHash(i);
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
void hashClass::del(int location)
|
||||
{
|
||||
strcpy(hashPtr[location].name, "");
|
||||
strcpy(hashPtr[location].number, "");
|
||||
hashPtr[location].exist = TRUE;
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
|
||||
void hashClass::delHash(int location)
|
||||
{
|
||||
strcpy(hashPtr[location].name, "");
|
||||
strcpy(hashPtr[location].number, "");
|
||||
hashPtr[location].exist = FALSE;
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
void hashClass::insert(int location, hashNode &newNode)
|
||||
{
|
||||
strcpy(hashPtr[location].name, newNode.name);
|
||||
strcpy(hashPtr[location].number, newNode.number);
|
||||
hashPtr[location].exist = TRUE;
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
void hashClass::save(fstream &fil)
|
||||
{
|
||||
int i = 0;
|
||||
while(i < ARRAYSIZE) {
|
||||
if((hashPtr[i].name[0]) && (hashPtr[i].exist == TRUE))
|
||||
fil.write((char*)& hashPtr[i],sizeof(hashPtr[i]));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
83
Hashing/header.hpp
Normal file
83
Hashing/header.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
//##################################################################
|
||||
// PROGRAMMERINGSUPPGIFT 3
|
||||
// DATASTRUKTURER OCH ALGORITMER
|
||||
// HASH TABELL
|
||||
//==================================================================
|
||||
// HEADER.HPP
|
||||
// Filen innehåller definition som används i programmet
|
||||
// Christian Ohlsson
|
||||
// Ingela Johansson
|
||||
// Anna-Maria Haglund
|
||||
// Karlstad 981007
|
||||
//==================================================================
|
||||
#ifndef _header_
|
||||
#define _header_
|
||||
|
||||
#include <iostream.h> //för in och utmatning
|
||||
#include <fstream.h> //för filhantering
|
||||
#include <iomanip.h> //för textmanipulation
|
||||
#include <string.h> //för strängmanipulation
|
||||
#include <conio.h> //för getch()
|
||||
#include <ctype.h> //för isalnum
|
||||
#include <stdlib.h> //för en massa saker
|
||||
|
||||
const int FALSE = 0; //boolsk variabel
|
||||
const int TRUE = !FALSE //boolsk variabel
|
||||
const int FILENAMESIZE = 8; //för MS-DOS 6.0
|
||||
const int NAMESIZE = 20; //antal tecken som kan matas in som namn
|
||||
const int NUMBERSIZE = 20; //antal tecken som kan matas in som nummer
|
||||
const int ENTER = 13; //ASCII kod för enter
|
||||
const int BACKSPACE = 8; //ASCII kod för backspace
|
||||
const int PRIMEARRAYSIZE = 30; //storlek på primtalsarrayen
|
||||
const int DEFAULTSIZE = 11; //hasharrayens defaultstorlek
|
||||
const int TABSIZE = 20; //antal steg som motsvarar TAB
|
||||
const int STEPSIZE = 7; //antal steg hash2 max stegar fram
|
||||
const int DEFAULTPRIMENUMBER = 4; //minsta primtalet i arrayen
|
||||
const int FIRSTPRIME = 3; //första talet som man jämför med
|
||||
const int STARTPRIME = 2; //första primtalet i arrayen
|
||||
const int PRIMESTEP = 2; //antal steg som man hoppar fram
|
||||
const float INSERTFACTOR = 0.8; //ger en omhashning när 80% är upptaget
|
||||
const float DELETEFACTOR = 0.3; //ger en omhashning när 30% är märkta deleted
|
||||
|
||||
typedef int bool; //definierar boolesk variabel
|
||||
typedef char nameType[NAMESIZE]; //sätter nametypen till char
|
||||
typedef char numberType[NUMBERSIZE]; //sätter numberTypen till char
|
||||
|
||||
struct hashNode{ //en nod
|
||||
nameType name;
|
||||
numberType number;
|
||||
bool exist;
|
||||
};
|
||||
|
||||
class hashClass
|
||||
{
|
||||
public:
|
||||
hashClass();
|
||||
~hashClass();
|
||||
bool search(nameType name);
|
||||
hashNode getNode(nameType &oneName);
|
||||
int hash1(nameType name);
|
||||
int hash2(int key);
|
||||
int getSize();
|
||||
void newHashArray();
|
||||
void reHash(int oldSize);
|
||||
void print();
|
||||
void prime();
|
||||
int checkOccupied();
|
||||
void destroyHash(int oldSize);
|
||||
bool biggerHash();
|
||||
bool anotherHash();
|
||||
void del(int location);
|
||||
void insert(int location, hashNode &newNode);
|
||||
void save(fstream &fil);
|
||||
hashNode *hashPtr;
|
||||
int nextPrime();
|
||||
private:
|
||||
void delHash(int location);
|
||||
bool isPrime(int nummer, int antal, int primeArray[PRIMEARRAYSIZE]);
|
||||
int ARRAYSIZE;
|
||||
int primeArray[];
|
||||
int PRIMENUMBER;
|
||||
};
|
||||
#endif
|
||||
|
||||
294
Hashing/huvud.cpp
Normal file
294
Hashing/huvud.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
//##################################################################
|
||||
// PROGRAMMERINGSUPPGIFT 3
|
||||
// DATASTRUKTURER OCH ALGORITMER
|
||||
// HASH TABELL
|
||||
//==================================================================
|
||||
// HUVUD.CPP
|
||||
// Filen innehåller huvudprogrammet
|
||||
// Christian Ohlsson
|
||||
// Ingela Johansson
|
||||
// Anna-Maria Haglund
|
||||
// Karlstad 981007
|
||||
//==================================================================
|
||||
|
||||
#include "header.hpp"
|
||||
|
||||
//###############################################################
|
||||
// SÄKER INMATNING AV MENYVAL
|
||||
// ser till att bara en character matas in
|
||||
// som menyval som dessutom måste vara en siffra
|
||||
//===============================================================
|
||||
char mataInChar()
|
||||
{
|
||||
bool test = FALSE;
|
||||
char temp, svar;
|
||||
do {
|
||||
temp = getch();
|
||||
if(isalnum(temp) && test == FALSE) {
|
||||
cout << temp;
|
||||
svar = temp;
|
||||
test = TRUE;
|
||||
}
|
||||
else if(temp == BACKSPACE && test == TRUE) {
|
||||
gotoxy(wherex()-1, wherey());
|
||||
cout << " ";
|
||||
gotoxy(wherex()-1, wherey());
|
||||
test = FALSE;
|
||||
}
|
||||
}while(temp != ENTER || test == FALSE);
|
||||
return svar;
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
//==================================================================
|
||||
void _insert(hashClass &hashTable)
|
||||
{
|
||||
nameType name;
|
||||
numberType number;
|
||||
hashNode newNode;
|
||||
int location;
|
||||
if(hashTable.biggerHash() == FALSE) {
|
||||
cout << "\n Skriv in namn: ";
|
||||
cin >> name;
|
||||
if(hashTable.search(name) == FALSE) {
|
||||
cout << "\n Skriv in nummer: ";
|
||||
cin >> number;
|
||||
strcpy(newNode.name, name);
|
||||
strcpy(newNode.number, number);
|
||||
location = hashTable.hash1(name);
|
||||
|
||||
if(hashTable.hashPtr[location].exist == FALSE)
|
||||
hashTable.insert(location, newNode);
|
||||
else
|
||||
while(hashTable.hashPtr[location].exist == TRUE) {
|
||||
location = location + hashTable.hash2(hashTable.hash1(newNode.name));
|
||||
if(location > hashTable.getSize())
|
||||
location = location - hashTable.getSize();
|
||||
if(hashTable.hashPtr[location].exist == FALSE) {
|
||||
hashTable.insert(location, newNode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
cout << "\n Du har redan satt in " << name << " i katalogen";
|
||||
getch();
|
||||
}
|
||||
}
|
||||
else
|
||||
hashTable.newHashArray();
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
// TAR BORT EN NOD UR TRÄD
|
||||
// calls: hashClass::del, getSize, search, hash1, hash2
|
||||
//==================================================================
|
||||
void _del(hashClass &hashTable)
|
||||
{
|
||||
nameType name;
|
||||
int location;
|
||||
|
||||
cout << "\n Vem vill du ta bort: ";
|
||||
cin >> name;
|
||||
if(hashTable.search(name)) {
|
||||
if(hashTable.anotherHash() == FALSE) {
|
||||
location = hashTable.hash1(name);
|
||||
if(strcmp(hashTable.hashPtr[location].name, name) == 0)
|
||||
hashTable.del(location);
|
||||
else {
|
||||
while(hashTable.hashPtr[location].exist == TRUE) {
|
||||
location = location + hashTable.hash2(hashTable.hash1(name));
|
||||
if(location > hashTable.getSize())
|
||||
location = location - hashTable.getSize();
|
||||
if(strcmp(hashTable.hashPtr[location].name, name) == 0)
|
||||
hashTable.del(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
hashTable.reHash(hashTable.getSize());
|
||||
}
|
||||
else {
|
||||
cout << " " << name << " finns inte i telefonkatalogen";
|
||||
getch();
|
||||
}
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
// SKRIVER UT I INORDER
|
||||
// calls: hashClass::print
|
||||
//==================================================================
|
||||
void _print(hashClass &hashTable)
|
||||
{
|
||||
int size = hashTable.getSize();
|
||||
clrscr();
|
||||
cout << "Plats"
|
||||
<< setw(TABSIZE-3)
|
||||
<< "Namn"
|
||||
<< setw(TABSIZE)
|
||||
<< "Nummer"
|
||||
<< "\n-------------------------------------------";
|
||||
for(int i=0 ; i < size ; i++)
|
||||
if(hashTable.hashPtr[i].exist == TRUE && hashTable.hashPtr[i].name[0])
|
||||
cout << endl
|
||||
<< i
|
||||
<< setw(TABSIZE)
|
||||
<< hashTable.hashPtr[i].name
|
||||
<< setw(TABSIZE)
|
||||
<< hashTable.hashPtr[i].number;
|
||||
cout << "\n\n\n\n Arrayen är nu " << size << " stor"
|
||||
<< "\n och " << hashTable.checkOccupied() << " platser är upptagna.";
|
||||
getch();
|
||||
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
// SÖKER I TRÄDET
|
||||
// calls: hashClass::search
|
||||
// calls: hashClass::isEmpty
|
||||
//==================================================================
|
||||
void _search(hashClass &hashTable)
|
||||
{
|
||||
hashNode newNode;
|
||||
nameType name;
|
||||
|
||||
cout << "\n Mata in namn: ";
|
||||
cin >> name;
|
||||
if(hashTable.search(name)) {
|
||||
newNode = hashTable.getNode(name);
|
||||
cout << "\n "
|
||||
<< newNode.name
|
||||
<< " har telefonnummer "
|
||||
<< newNode.number
|
||||
<< ".";
|
||||
}
|
||||
else
|
||||
cout << " " << name << " finns inte i telefonkatalogen";
|
||||
getch();
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
// SPARAR TRÄDET PÅ FIL
|
||||
// calls: hashClass::save
|
||||
// calls: hashClass::isEmpty
|
||||
//==================================================================
|
||||
void _save(hashClass &hashTable)
|
||||
{
|
||||
fstream fil;
|
||||
char filnamn[FILENAMESIZE];
|
||||
cout << "\n Ange filnamn att spara: ";
|
||||
cin >> filnamn;
|
||||
fil.open(filnamn,ios::out|ios::binary);
|
||||
hashTable.save(fil);
|
||||
fil.close();
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
// HÄMTAR ETT TRÄD FRÅN EN FIL
|
||||
// läser in värdet i varje nod i preorder
|
||||
// och sätter in det i trädet i preoder
|
||||
// calls hashClass::insert
|
||||
// calls: hashClass::isEmpty
|
||||
//==================================================================
|
||||
void _load(hashClass &hashTable)
|
||||
{
|
||||
fstream fil;
|
||||
int i = 0;
|
||||
char filnamn[FILENAMESIZE];
|
||||
cout << "\n Ange filnamn att hämta: ";
|
||||
cin >> filnamn;
|
||||
hashTable.destroyHash(hashTable.getSize());
|
||||
fil.open(filnamn,ios::in|ios::binary);
|
||||
if(fil) {
|
||||
while(fil.peek() != EOF) {
|
||||
fil.read((char*)& hashTable.hashPtr[i],sizeof(hashTable.hashPtr[i]));
|
||||
hashTable.insert(i, hashTable.hashPtr[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cerr << "\n Filen finns inte...";
|
||||
getch();
|
||||
}
|
||||
hashTable.reHash(hashTable.getSize());
|
||||
fil.close();
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
// DESTROYTREE
|
||||
// tar bort hela trädet
|
||||
// calls: hashClass::isEmpty
|
||||
// calls: hashClass::destroyHash
|
||||
//==================================================================
|
||||
void _destroyHash(hashClass &hashTable)
|
||||
{
|
||||
hashTable.destroyHash(hashTable.getSize());
|
||||
cerr << "\n Telefonkatalogen är tom...";
|
||||
getch();
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
// MENY ITEMS
|
||||
// skriver ut menyn på skärmen
|
||||
//==================================================================
|
||||
void meny()
|
||||
{
|
||||
clrscr();
|
||||
cout << " \n TELEFON KATALOGEN "
|
||||
<< " \n ----------------- "
|
||||
<< " \n 1. Lägg till person "
|
||||
<< " \n 2. Ta bort person "
|
||||
<< " \n 3. Sök efter person "
|
||||
<< " \n 4. Skriv ut "
|
||||
<< " \n 5. Spara på fil "
|
||||
<< " \n 6. Hämta från fil "
|
||||
<< " \n 7. Radera hela katalogen "
|
||||
<< " \n 0. Avsluta ";
|
||||
gotoxy(2,12); //ställer markören under menyn
|
||||
}
|
||||
//##################################################################
|
||||
//Function:
|
||||
//Task:
|
||||
//Calls:
|
||||
// MAIN FUNCTION
|
||||
// skapar trädet hashTable av typen hashClass
|
||||
// calls: alla drivrutiner
|
||||
//==================================================================
|
||||
void main()
|
||||
{
|
||||
hashClass hashTable;
|
||||
char val;
|
||||
do {
|
||||
meny();
|
||||
val = mataInChar();
|
||||
switch (val)
|
||||
{
|
||||
case '1' : _insert(hashTable);break;
|
||||
case '2' : _del(hashTable);break;
|
||||
case '3' : _search(hashTable);break;
|
||||
case '4' : _print(hashTable);break;
|
||||
case '5' : _save(hashTable);break;
|
||||
case '6' : _load(hashTable);break;
|
||||
case '7' : _destroyHash(hashTable);break;
|
||||
case '0' : cout << "\n Programmet avslutat";break;
|
||||
default : cerr << "\n Felaktigt val";getch();
|
||||
}
|
||||
}while(val != '0');
|
||||
exit(0);
|
||||
}
|
||||
144
Simulering/lab1.cpp
Normal file
144
Simulering/lab1.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/* *********************************************************************** */
|
||||
/* lab1.cpp 980910 */
|
||||
/* Innehåller köhantering */
|
||||
/* *********************************************************************** */
|
||||
/* Daniel Westerberg */
|
||||
/* Christian Ohlsson */
|
||||
/* Anna-Maria Haglund */
|
||||
/* Ingela Johansson */
|
||||
/* Charlotta Lagerkvist */
|
||||
/* *********************************************************************** */
|
||||
#include "lab1.hpp"
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* constructorn */
|
||||
/* Nollställer variabler */
|
||||
/* INPUT: inget */
|
||||
/* OUTPUT: inget */
|
||||
/* *********************************************************************** */
|
||||
queue::queue()
|
||||
{
|
||||
first = NULL;
|
||||
last = NULL;
|
||||
cur = NULL;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* destructorn */
|
||||
/* Tömmer listan */
|
||||
/* INPUT: inget */
|
||||
/* OUTPUT: inget */
|
||||
/* *********************************************************************** */
|
||||
queue::~queue()
|
||||
{
|
||||
cur = first;
|
||||
while (cur)
|
||||
{
|
||||
first = cur;
|
||||
cur = cur->next;
|
||||
delete first;
|
||||
}
|
||||
first = NULL;
|
||||
last = NULL;
|
||||
cur = NULL;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* enqueue() */
|
||||
/* ställer en person med ett antal varor i kön */
|
||||
/* INPUT: antal varor */
|
||||
/* OUTPUT: bool */
|
||||
/* *********************************************************************** */
|
||||
bool queue::enqueue(int v)
|
||||
{
|
||||
if (cur = new kund)
|
||||
{
|
||||
cur->next=NULL;
|
||||
cur->varor = v;
|
||||
if (first == NULL)
|
||||
first = cur;
|
||||
else
|
||||
last->next = cur;
|
||||
last = cur;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* dequeue() */
|
||||
/* tar bort en person ur kön */
|
||||
/* INPUT: inget */
|
||||
/* OUTPUT: bool */
|
||||
/* *********************************************************************** */
|
||||
bool queue::dequeue()
|
||||
{
|
||||
if (cur = first)
|
||||
{
|
||||
if ((first = first->next) == NULL)
|
||||
last=NULL;
|
||||
delete cur;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* warez() */
|
||||
/* kollar hur lång varje kö är, tidsmässigt! */
|
||||
/* INPUT: inget */
|
||||
/* OUTPUT: tiden för varje kund baserad på antal varor */
|
||||
/* *********************************************************************** */
|
||||
int queue::warez()
|
||||
{
|
||||
int x=0;
|
||||
cur = first;
|
||||
while (cur)
|
||||
{
|
||||
x += cur->varor*R + B; // räknar ut tiden för varje kund + 'x'
|
||||
cur = cur->next;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* pay() */
|
||||
/* betalningsfunktion, returnerar antalet varor kvar att betala */
|
||||
/* INPUT: antal varor att läggas till */
|
||||
/* OUTPUT: antal varor för första kunden i kön */
|
||||
/* *********************************************************************** */
|
||||
int queue::pay(int v)
|
||||
{
|
||||
if (first)
|
||||
return (first->varor += v); // lägger till 'v' och returnerar
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* queueSize() */
|
||||
/* returnerar antalet kunder i kön */
|
||||
/* INPUT: inget */
|
||||
/* OUTPUT: Antal kunder i kön */
|
||||
/* *********************************************************************** */
|
||||
int queue::queueSize()
|
||||
{
|
||||
int x=0;
|
||||
cur = first;
|
||||
while (cur)
|
||||
{
|
||||
cur = cur->next;
|
||||
x++;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* isEmpty() */
|
||||
/* kollar om en kö är tom */
|
||||
/* INPUT: inget */
|
||||
/* OUTPUT: TRUE om listan är tom */
|
||||
/* *********************************************************************** */
|
||||
bool queue::isEmpty() { return (first == NULL) ; }
|
||||
57
Simulering/lab1.hpp
Normal file
57
Simulering/lab1.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/* *********************************************************************** */
|
||||
/* lab1.hpp 980910 */
|
||||
/* Headerfil för lab1 */
|
||||
/* *********************************************************************** */
|
||||
/* Daniel Westerberg */
|
||||
/* Christian Ohlsson */
|
||||
/* Anna-Maria Haglund */
|
||||
/* Ingela Johansson */
|
||||
/* Charlotta Lagerkvist */
|
||||
/* *********************************************************************** */
|
||||
|
||||
#include <dos.h>
|
||||
#include <conio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream.h>
|
||||
|
||||
typedef int bool;
|
||||
const bool TRUE=-1, FALSE=0;
|
||||
|
||||
const int K=6; //Konstant för antal kassor
|
||||
const int R=8; //Konstant för antal sekunder per vara
|
||||
const int B=20; //Konstant för betalning
|
||||
const int T=100; //Konstant för hur mycket snabbare än real-time det går
|
||||
const int MS=1000; //Konstant för antal ms på en sekund
|
||||
const int SPM=60; //Antal sekunder per minut
|
||||
const int STARTTID=9*SPM*SPM+SPM; //Gör att programmet startar 9.01
|
||||
const int MOVEX=5; //Antal steg att flytta i X-led
|
||||
const int CENT=100; //Ger 100% att starta med
|
||||
const int FALL1=10; //Ger 10% chans
|
||||
const int FALL2=40; //Ger 30% chans
|
||||
const int FALL3=90; //Ger 50% chans
|
||||
const int MAV=40; //Ger slumptal mellan 1 - 40
|
||||
|
||||
class queue
|
||||
{
|
||||
private:
|
||||
typedef struct kund
|
||||
{
|
||||
struct kund *next;
|
||||
int varor;
|
||||
} kund;
|
||||
|
||||
kund *first;
|
||||
kund *last;
|
||||
kund *cur;
|
||||
|
||||
public:
|
||||
char r;
|
||||
queue();
|
||||
~queue();
|
||||
bool enqueue(int);
|
||||
bool dequeue();
|
||||
int warez();
|
||||
int pay(int);
|
||||
int queueSize();
|
||||
bool isEmpty();
|
||||
};
|
||||
123
Simulering/main.cpp
Normal file
123
Simulering/main.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/* *********************************************************************** */
|
||||
/* main.cpp 980910 */
|
||||
/* Innehåller huvudprogram för köhantering */
|
||||
/* *********************************************************************** */
|
||||
/* Daniel Westerberg */
|
||||
/* Christian Ohlsson */
|
||||
/* Anna-Maria Haglund */
|
||||
/* Ingela Johansson */
|
||||
/* Charlotta Lagerkvist */
|
||||
/* *********************************************************************** */
|
||||
#include "lab1.hpp"
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* Klassarray */
|
||||
/* *********************************************************************** */
|
||||
class queue q[K];
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* funktionsprototyper som denna fil innehåller */
|
||||
/* *********************************************************************** */
|
||||
void betala(int);
|
||||
void print(long);
|
||||
void addkund(void);
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* main med huvud-loop och delay */
|
||||
/* *********************************************************************** */
|
||||
void main()
|
||||
{
|
||||
long clock=STARTTID;
|
||||
int kund=0;
|
||||
|
||||
while(!kbhit())
|
||||
{
|
||||
print(clock++);
|
||||
if (++kund == SPM)
|
||||
{
|
||||
addkund();
|
||||
kund=0;
|
||||
}
|
||||
for(int x=0; x<K; x++)
|
||||
betala(x);
|
||||
delay(MS/T);
|
||||
}
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* print() */
|
||||
/* skriver ut allting på skärmen */
|
||||
/* INPUT: klockan */
|
||||
/* OUTPUT: Tiden på skärmen */
|
||||
/* *********************************************************************** */
|
||||
void print(long cl)
|
||||
{
|
||||
for(int x=0; x<K; x++)
|
||||
{
|
||||
gotoxy(2,x+MOVEX);
|
||||
cout << "Kassa nr " << (x+1) << "; Varor: " << q[x].pay(0) << ' ';
|
||||
gotoxy(23,x+MOVEX);
|
||||
cout << ", Kunder: " << q[x].queueSize() << ' ';
|
||||
}
|
||||
gotoxy(1,1);
|
||||
cout<<"Tid: "<<(cl/(SPM*SPM))<<':'<<((cl/SPM)%SPM)<<':'<<(cl%SPM)<<" ";
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* betala() */
|
||||
/* beräknar tiden för varorna och tar bort varor och kunder */
|
||||
/* INPUT: position i klassarray */
|
||||
/* OUTPUT: inget */
|
||||
/* *********************************************************************** */
|
||||
void betala(int pos)
|
||||
{
|
||||
if(q[pos].isEmpty()==0)
|
||||
if(q[pos].pay(0))
|
||||
{
|
||||
q[pos].r++;
|
||||
if(q[pos].r==R)
|
||||
if(q[pos].pay(-1)==0)
|
||||
q[pos].r=B;
|
||||
else
|
||||
q[pos].r=0;
|
||||
}
|
||||
else
|
||||
if(q[pos].r>0)
|
||||
q[pos].r--;
|
||||
else
|
||||
q[pos].dequeue();
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* addkund() */
|
||||
/* lägger till en kund med ett slumpmässigt antal varor i den minsta kön */
|
||||
/* INPUT: inget */
|
||||
/* OUTPUT: inget */
|
||||
/* *********************************************************************** */
|
||||
void addkund()
|
||||
{
|
||||
int in, x, min, pos=0;
|
||||
unsigned int slumptal;
|
||||
srand((unsigned) time(NULL));
|
||||
slumptal = rand()%CENT;
|
||||
if (slumptal < FALL1)
|
||||
in=0;
|
||||
else if (slumptal < FALL2)
|
||||
in=1;
|
||||
else if (slumptal < FALL3)
|
||||
in=2;
|
||||
else
|
||||
in=3;
|
||||
while(in)
|
||||
{
|
||||
min=q[0].warez();
|
||||
for(x=1; x<K; x++)
|
||||
if (min>q[x].warez())
|
||||
{
|
||||
min=q[x].warez();
|
||||
pos=x;
|
||||
}
|
||||
q[pos].enqueue(rand()%MAV+1);
|
||||
in--;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user