山东大学软件学院2017-18学年大二数据结构实验五、六、七

注:实验代码均为自己编写,均能满足实验要求,但实现方法不唯一仅供参考。

实验五 二叉树操作

1.实验内容(题目内容,输入要求,输出要求)

  1. 输入一个完全二叉树的层次遍历字符串,创建这个二叉树,输出这个二叉树的前序遍历字符串、中序遍历字符串、后序遍历字符串、结点数目、二叉树高度(上述每一个结果独立一行显示)。
  2. 输入二叉树前序序列和中序序列(各元素各不相同),创建这个二叉树,输出该二叉树的后序序列、层次遍历。

2.数据结构与算法描述 (整体思路描述,所需要的数据结构与算法)

  • 运用链表实现二叉树,树节点中有数据域与两个地址域(左右孩子)。
  • 层次遍历创建二叉树时,运用队列处理当前节点的左右子节点,其中对输入的char数组运用二叉树的线性公式化描述去为链表实现二叉树中的节点赋值,某个节点的子节点在数组中的位置分别为2i+1与2i+2。
  • 前序中序后序遍历二叉树均采用递归方法。
  • 结点数目运用前序遍历的函数结构把visit改成结点数count++
  • 二叉树高度用递归实现,分别对左右子树进行递归,返回判断的时候比较左右字数高度返回高的那棵树的高度,如果一样高返回右子树的高度+1。
  • 前序中序生成二叉树利用前序中第一个元素先找到中序的根节点处,然后用current标记,左侧为左子树右侧为右子树。此时前序加一便是中序current所指根节点的左子树的根,然后利用递归,分别生成左右子树。

3.实现源代码

#include<iostream>

#include<string>

#include<queue>

using namespace std;

 

template<class T>

class BinaryTreeNode

{

    template<class T> friend class BinaryTree;

public:

    BinaryTreeNode() { LeftChild = RightChild = NULL; };

    BinaryTreeNode(const T & data) { this->data = data; LeftChild = RightChild = NULL; };

    BinaryTreeNode(const T & data, BinaryTreeNode* l, BinaryTreeNode* r) { this->data = data; LeftChild = l; RightChild = r; };

private:

    T data;

    BinaryTreeNode *LeftChild;

    BinaryTreeNode *RightChild;

};

 

template<class T>

class BinaryTree

{

public:

    BinaryTreeNode<T> *root;

    BinaryTree() { root = 0; _count = 0; };

    ~BinaryTree() {};

    void MakeTreeByLevelOrder(const char* levelOrder, const int length);

    void MakeTreeByPreOrderAndInOrder(const char* preOrder, const char* inOrder, const int length);

    void MakeTreeByPreOrderAndInOrder(BinaryTreeNode<T>& t, const char* preOrder,int p1,int p2, const char* inOrder,int i1,int i2);

    int Height()const { return Height(root); }

    int NodeNumber(BinaryTreeNode<T> *x) {

       if (x) {

        _count++;                    //把visit一个节点改成节点数加一

            NodeNumber(x->LeftChild);

             NodeNumber(x->RightChild);

       }

         return _count;

    }

    void visit(BinaryTreeNode<T> *x) { if (x->data != NULL) { cout << x->data; cout << ","; } }

 

    void levelOrder(BinaryTreeNode<T> *t)   //层次遍历

    {

        queue<BinaryTreeNode<T>*> Q;

        while (t)

        {

            visit(t);                                  //访问t并将t的左右孩子放入队列

            if (t->LeftChild) Q.push(t->LeftChild);

            if (t->RightChild) Q.push(t->RightChild);

            if (!Q.empty()) {

                t = Q.front();

                Q.pop();                              //访问下一个节点 此时t被赋为了队列的第一个元素

            }

            else

            {

                return;

            }

        }

    }

 

    void preOrder(BinaryTreeNode<T> *t)     //前序遍历

    {

        if (t)

        {

            visit(t);

            preOrder(t->LeftChild);

            preOrder(t->RightChild);

        }

    }

 

    void inOrder(BinaryTreeNode<T> *t)     //中序遍历

    {

        if (t != NULL)

        {

            inOrder(t->LeftChild);

            visit(t);

            inOrder(t->RightChild);

        }

    }

 

    void postOrder(BinaryTreeNode<T> *t)     //后序遍历

    {

        if (t != NULL)

        {

            postOrder(t->LeftChild);

            postOrder(t->RightChild);

            visit(t);

        }

    }

 

private:

    int _count; 

    int Height(BinaryTreeNode<T>*t)const;

};

 

template<class T>

void BinaryTree<T>::MakeTreeByLevelOrder(const char* levelOrder, const int length)

{

    queue<BinaryTreeNode<T>*> queue;   //运用队列处理左右节点

 

    for (int i = 0; i < length; i++)

    {

        if (i == 0)  //root根的处理 树根的初始化

        {

            switch (length)

            {

            case 1:

                root = new BinaryTreeNode<T>(levelOrder[0]);

                break;

            case 2:

                root = new BinaryTreeNode<T>(levelOrder[0], new BinaryTreeNode<T>(levelOrder[1]),NULL);

                break;

            case 3:

                root = new BinaryTreeNode<T>(levelOrder[0], new BinaryTreeNode<T>(levelOrder[1]), new BinaryTreeNode<T>(levelOrder[2]));

                break;

            default:

                root = new BinaryTreeNode<T>(levelOrder[0], new BinaryTreeNode<T>(levelOrder[1]), new BinaryTreeNode<T>(levelOrder[2]));

                queue.push(root->LeftChild);

                queue.push(root->RightChild);

                break;

            }

        }

        else     //不为根节点时

        {

            if (2 * i + 2 <= length-1)         //如果当前节点有右孩子

            {

                queue.front()->LeftChild = new BinaryTreeNode<T>(levelOrder[2 * i + 1]);

                queue.front()->RightChild = new BinaryTreeNode<T>(levelOrder[2 * i + 2]);

                queue.push(queue.front()->LeftChild);

                queue.push(queue.front()->RightChild);

                queue.pop();

            }

            if (2 * i + 2 > length-1 && 2 * i + 1 <= length-1)      //如果当前节点 没有右孩子且 有左孩子

            {

                queue.front()->LeftChild = new BinaryTreeNode<T>(levelOrder[2 * i + 1]);

                queue.pop();

            }

        }

    }

}

 

template<class T>

void BinaryTree<T>::MakeTreeByPreOrderAndInOrder(const char* preOrder, const char* inOrder, const int length)

{

    root = new BinaryTreeNode<T>();

    MakeTreeByPreOrderAndInOrder(*root, preOrder, 0, length - 1, inOrder, 0, length - 1);

}

 

template<class T>

void BinaryTree<T>::MakeTreeByPreOrderAndInOrder(BinaryTreeNode<T>& t, const char * preOrder, int p1, int p2, const char * inOrder, int i1, int i2)

{

    //i1为inOrder的开头,p1为preOrder的开头,i2p2分别为结尾

    t.data = preOrder[p1];                

    t.LeftChild = t.RightChild = NULL;           //根的构建

    int current = i1;                            //从中序i1处 声明current位置

    while (inOrder[current] != preOrder[p1])    //用current记录与前序p1位置相同数的位置

        current++;

    int length = current - i1;                  //记录current根左子树的长度

    if (current > i1) {                         //如果current有左子树就新建他的LeftChild并且用递归

        t.LeftChild = new BinaryTreeNode<T>(); 

        MakeTreeByPreOrderAndInOrder(*(t.LeftChild), preOrder, p1 + 1, p1 + length, inOrder, i1, current - 1);//inOrder的左树

    }

    if (current < i2) {

        t.RightChild = new BinaryTreeNode<T>();  //如果current有右子树就新建他的RightChild并且用递归

        MakeTreeByPreOrderAndInOrder(*(t.RightChild), preOrder, p1 + length + 1, p2, inOrder, current + 1, i2);//inOrder的右树

    }

}

 

 

template<class T>

int BinaryTree<T>::Height(BinaryTreeNode<T>* t) const

{

    if (!t) return 0;

 

    int heightOfLeft = Height(t->LeftChild);

    int heightOfRight = Height(t->RightChild);

    if (heightOfLeft > heightOfRight)

    {

        return ++heightOfLeft;

    }

    else

    {

        return ++heightOfRight;

    }

 

}

 

int main() {

    cout << "Input1" << endl;

    string levelOrderString;

    cin >> levelOrderString;

    const char*levelOrder = levelOrderString.c_str();

    BinaryTree<char>*a = new BinaryTree<char>();

    a->MakeTreeByLevelOrder(levelOrder, levelOrderString.length());

    cout << "Output1" << endl;

    a->preOrder(a->root);

    cout << endl;

    a->inOrder(a->root);

    cout << endl;

    a->postOrder(a->root);

    cout << endl;

    cout<< a->NodeNumber(a->root)<<endl;

    cout << a->Height() << endl;

    cout << "Input2" << endl;

    string preOrderString;

    cin >> preOrderString;

    const char*preOrder = preOrderString.c_str();

    string inOrderString;

    cin >> inOrderString;

    const char*inOrder = inOrderString.c_str();

    BinaryTree<char>*b = new BinaryTree<char>();

    b->MakeTreeByPreOrderAndInOrder(preOrder, inOrder, preOrderString.length());

    cout << "Output2" << endl;

    b->postOrder(b->root);

    cout << endl;

    b->levelOrder(b->root);

    cout << endl;

    cout << "End" << endl;

    system("pause");

}

实验六 堆和搜索树

1.实验内容(题目内容,输入要求,输出要求)

  1. 输入一系列不为零的正整数(最多不超过20个),遇到0代表输入结束(不包含0)。
  2. 根据输入的数据,创建最大堆,输出最大堆的层次序列。
  3. 输出用堆排序后的排序结果。
  4. 根据输入的数据,创建二叉搜索树,输出二叉搜索树的前序序列。
  5. 输出二叉搜索树的中序序列。
  6. 根据输入的数据作为字母出现的频率(第1个数代表A频率,第2个数代表B频率,……),创建Huffman树,输出Huffman编码,要求左子树权值小于右子树权值,左边为0,右边为1。输出按字数顺序由小到大输出,格式采用“字母:编码”,例如A:0,B:10……

2.数据结构与算法描述 (整体思路描述,所需要的数据结构与算法)

①、前五题运用最大堆及堆排序、最后一题运用最小堆生成霍夫曼树,运用递归实现霍夫曼编码的输出。

②、采用数组的形式实现最大堆,从2分之数组大小处向前依次移动,通过position不断*2来比较此时节点与其子节点中最大的一个数的大小,如果比其子节点中最大的一个数还大那么就不动,否则就把大孩子覆盖到该节点处,该节点下移到其子节点位置接着向下2*position处重复比较。

③、堆排序用不断删除堆顶最大元素在for循环中i--进行从小到大的排序。

④、构造二叉搜索树通过依次加入数据从root节点依次向下比较,小的放左面大的放右面。

⑤、首先按构造最大堆的方式构造最小堆,然后定义霍夫曼类 其中有生成霍夫曼编码的方法,与私有变量一个霍夫曼树节点 一个权重。另外单独一个生成霍夫曼树的方法,其中先声明一个霍夫曼类型的数组,其中的权重与霍夫曼节点全部赋值,霍夫曼节点的data为ABCD...符号 权重为输入的数据。

再定义一个存霍夫曼类型的最小堆,通过其权重进行排序,每次取权重最小的两个生成一个霍夫曼类,其data为0,权重为两节点相加,生成后再插入最小堆中,然后不断进行取两个生成一个的操作,直到最后返回剩下的最后一个节点,即为生成好的霍夫曼树的根节点。

⑥、霍夫曼编码通过递归,不断从根节点遍历到每个叶子节点,其中向左走字符串+0,向右走字符串+1,最后输出每个符号的霍夫曼编码。

3.实现源代码

#include<iostream>

#include<queue>

#include<string>

using namespace std;

 

template<class T>

class MaxHeap

{

public:

    MaxHeap() {

        currentSize = 0;   //数组中从1开始

    }

    int Size()const { return currentSize; }

    void creat(T a[], int size);

    void outputByLevelOrder();

    MaxHeap<T>& DeleteMax(T &x);

    void HeapSort(int size);

    T *heap;

private:

    int maxSize=20;

    int currentSize;

};

 

template<class T>

void MaxHeap<T>::creat(T a[], int size)

{

    heap = a;

    currentSize = size;

    for (int i = currentSize/2; i >= 1; i--)

    {

        T rootOfChild = heap[i];//记录子树的根的值

        int position = 2 * i;   //子树根如果移动的话应该在的位置

        while (position<=currentSize)

        {

            if (position<currentSize&&heap[position]<heap[position+1])  //如果当前元素有右孩子并且左孩子小于右孩子

            {

                position++;                         //position指到右孩子的位置 否则position还在左孩子位置

            }

            if (rootOfChild >= heap[position])      //如果此时子树根大于两孩子中最大的一个跳出循环 位置不变

            {

                break;

            }

            heap[position / 2] = heap[position];            //否则 孩子中最大的内个覆盖子树根位置的值

            position *= 2;                                 //再把position指到内个大孩子的左子树根处 重复循环

        }

        heap[position / 2] = rootOfChild;

    }

}

 

template<class T>

void MaxHeap<T>::outputByLevelOrder()

{

    for (int i = 1; i <=currentSize; i++)

    {

        cout << heap[i];

        if (i!=currentSize)

        {

            cout << ",";

        }

        else

        {

            cout << endl;

        }

    }

}

 

template<class T>

MaxHeap<T>& MaxHeap<T>::DeleteMax(T & x//将最大元素放入x,并从堆中删除最大元素

{

    if (currentSize == 0)  //如果堆为空返回

        return *this;

    x = heap[1];

    T y = heap[currentSize--];//保存最后一个元素

    int i = 1;                //堆的当前节点

    int position = 2;

    while (position <= currentSize) {

        if (position<currentSize&&heap[position + 1]>heap[position]) //如果当前元素有右孩子并且左孩子小于右孩子

            position++;                             //position指到右孩子的位置 否则position还在左孩子位置

        if (y >= heap[position])               //如果此时最后一个元素大于当前节点两孩子中最大的一个跳出循环

            break;

        heap[i] = heap[position];          //否则 孩子中最大的内个覆盖子树根位置的值

        i = position;                     

        position *=2;                      //再把position指到内个大孩子的左子树根处 重复循环

    }

    heap[i] = y;                //把最后一个元素放到i处

    return *this;

}

 

template<class T>

void MaxHeap<T>::HeapSort(int size)

{

    T x;

    for (int i =size; i >=1 ; i--)   //对当前堆进行最大堆排序

    {

        this->DeleteMax(x);

        this->heap[i] = x;

    }

    for (int i = 1; i <= size; i++)   //输出最大堆排序后的结果

    {

        cout << heap[i];

        if (i != size)

        {

            cout << ",";

        }

        else

        {

            cout << endl;

        }

    }

}

 

 

 

template<class T>

class BinaryTreeNode

{

    friend class Huffman;

    template<class T> friend class BinaryTree;

public:

    BinaryTreeNode() { LeftChild = RightChild = NULL; };

    BinaryTreeNode(const T & data) { this->data = data; LeftChild = RightChild = NULL; };

    BinaryTreeNode(const T & data, BinaryTreeNode* l, BinaryTreeNode* r) { this->data = data; LeftChild = l; RightChild = r; };

private:

    T data;

    BinaryTreeNode *LeftChild;

    BinaryTreeNode *RightChild;

};

 

template<class T>

class BinaryTree

{

public:

    BinaryTreeNode<T> *root;

    BinaryTree() { root = 0;};

    ~BinaryTree() {};

    void visit(BinaryTreeNode<T> *x) { if (x->data != NULL) { cout << x->data; cout << ","; } }

    BinaryTree<T> makeSearchTree(const T &e);

    void levelOrder(BinaryTreeNode<T> *t)   //层次遍历

    {

        queue<BinaryTreeNode<T>*> Q;

        while (t)

        {

            visit(t);                                  //访问t并将t的左右孩子放入队列

            if (t->LeftChild) Q.push(t->LeftChild);

            if (t->RightChild) Q.push(t->RightChild);

            if (!Q.empty()) {

                t = Q.front();

                Q.pop();                              //访问下一个节点 此时t被赋为了队列的第一个元素

            }

            else

            {

                return;

            }

        }

    }

 

    void preOrder(BinaryTreeNode<T> *t)     //前序遍历

    {

        if (t)

        {

            visit(t);

            preOrder(t->LeftChild);

            preOrder(t->RightChild);

        }

    }

 

    void inOrder(BinaryTreeNode<T> *t)     //中序遍历

    {

        if (t != NULL)

        {

            inOrder(t->LeftChild);

            visit(t);

            inOrder(t->RightChild);

        }

    }

 

private:

   

};

 

template<class T>

BinaryTree<T> BinaryTree<T>::makeSearchTree(const T &e)

{

    BinaryTreeNode<T> *current = root;

    BinaryTreeNode<T> *before = 0;

    while (current)

    {

        before = current;                     //记录应该插入到谁的后面 由于current最后为null 所以要跟一个

        if (e < current->data) current = current->LeftChild;

        else if (e > current->data) current = current->RightChild;

    }

 

    BinaryTreeNode<T> *element = new BinaryTreeNode<T>(e);

    if (root)

    {

        if (e < before->data) before->LeftChild = element;

        else  before->RightChild = element;

    }

    else

    {

        root = element;

    }

    return *this;

}

 

template<class T>

class MinHeap

{

public:

    MinHeap() {

        currentSize = 0;   //数组中从1开始

    }

    int Size()const { return currentSize; }

    void creat(T a[], int size);

    void outputByLevelOrder()

    {

        for (int i = 1; i <= currentSize; i++)

        {

            cout << heap[i];

            if (i != currentSize)

            {

                cout << ",";

            }

            else

            {

                cout << endl;

            }

        }

    }

    MinHeap<T>& Insert(const T&x);

    MinHeap<T>& DeleteMin(T &x);

    T *heap;

private:

    int maxSize = 20;

    int currentSize;

};

 

template<class T>

void MinHeap<T>::creat(T a[], int size)

{

    heap = a;

    currentSize = size;

    for (int i = currentSize / 2; i >= 1; i--)

    {

        T rootOfChild = heap[i];//记录子树的根的值

        int position = 2 * i;   //子树根如果移动的话应该在的位置

        while (position <= currentSize)

        {

            if (position<currentSize&&heap[position]>heap[position + 1])  //如果当前元素有右孩子并且左孩子大于右孩子

            {

                position++;                         //position指到右孩子的位置 否则position还在左孩子位置

            }

            if (rootOfChild < heap[position])      //如果此时子树根小于两孩子中最小的一个跳出循环 位置不变

            {

                break;

            }

            heap[position / 2] = heap[position];            //否则 孩子中最小的内个覆盖子树根位置的值

            position *= 2;                                 //再把position指到内个小孩子的左子树根处 重复循环

        }

        heap[position / 2] = rootOfChild;

    }

}

 

template<class T>

MinHeap<T>& MinHeap<T>::Insert(const T & x)

{

    if (currentSize == maxSize)

        return *this;

    currentSize++;

    int position = currentSize;

    while (position>1)

    {

        if (x>=heap[position/2])

        {

            heap[position] = x;

            break;

        }

        heap[position] = heap[position/ 2];   //下移父节点

        position = position / 2;

    }

    heap[position] = x;

    return *this;

}

 

template<class T>

MinHeap<T>& MinHeap<T>::DeleteMin(T & x//将最大元素放入x,并从堆中删除最大元素

{

    if (currentSize == 0)  //如果堆为空返回

        return *this;

    x = heap[1];

    int last = currentSize;

    T y = heap[last];//保存最后一个元素

    int i = 1;                //堆的当前节点

    int position = 2;

    while (position <= currentSize) {

        if (position<currentSize&&heap[position + 1]<heap[position]) //如果当前元素有右孩子并且左孩子大于右孩子

            position++;                             //position指到右孩子的位置 否则position还在左孩子位置

        if (y <= heap[position])               //如果此时最后一个元素小于当前节点两孩子中最大的一个跳出循环

            break;

        heap[i] = heap[position];          //否则 孩子中最大的内个覆盖子树根位置的值

        i = position;

        position *= 2;                      //再把position指到内个大孩子的左子树根处 重复循环

    }

    heap[i] = y;                //把最后一个元素放到i处

    currentSize--;

    return *this;

}

 

int number = 0;

string *huffmancode1 = new string[20];

class Huffman

{

    friend BinaryTree<char> HuffmanTree(int[], int);

public:

    operator int()const { return weight; }

    void HuffmanCode(BinaryTree<char> HuffmanTree, string code) {

        BinaryTreeNode<char> *t;

        BinaryTree<char> Left, Right;

        t = HuffmanTree.root;

        if (!t->LeftChild && !t->RightChild) {

            int symbolposition = t->data - 'A';

            huffmancode1[symbolposition] = code;

            number++;

        }else{

            if (t->LeftChild)

            {

                Left.root = t->LeftChild;

                HuffmanCode(Left, code+"0");

            }

            if (t->RightChild)

            {

                Right.root = t->RightChild;

                HuffmanCode(Right, code+"1");

            }

        }

       

 

    }

private:

    BinaryTreeNode<char> *HuffmanTreeNode;

    int weight;

};

 

 

BinaryTree<char> HuffmanTree(int a[], int n) {

    Huffman *w = new Huffman[n+1];  //底下从1开始

    char symbol = 'A';

    for (int i = 1; i <=n; i++)

    {

        w[i].weight = a[i];

        w[i].HuffmanTreeNode = new BinaryTreeNode<char>(symbol);

        symbol++;

    }

 

    MinHeap<Huffman>minheap;

    minheap.creat(w, n);

    Huffman x, y;

    for (int  i = 1; i < n; i++)

    {

        minheap.DeleteMin(x);

        minheap.DeleteMin(y);

        BinaryTreeNode<char> *z = new BinaryTreeNode<char>(0,x.HuffmanTreeNode,y.HuffmanTreeNode);

        x.weight += y.weight;

        x.HuffmanTreeNode = z;

        minheap.Insert(x);

    }                                            

    minheap.DeleteMin(x);

    BinaryTree<char> huffmantree;

    huffmantree.root = x.HuffmanTreeNode;

    return huffmantree;

}

 

 

 

int main(){

    cout << "Input1" << endl;

    int array[21];            //创建一个最多可输入20个数的数组

    int array2[21];

    int n, m;                 //n为当前输入的数据

    for (int i = 1; i <= 21; i++)

    {

        cin >> n;

        if (n == 0) {

            m = i - 1;            //m为了记住0前一共输入了几个数 由于array【0】没有数据 故-1

            break;

        }

        if (i==21)

        {

            array[i] = n;

            array2[i] = n;

            break;

        }

        array[i] = n;

        array2[i] = n;

    }

 

    MaxHeap<int> *a = new MaxHeap<int>();

    a->creat(array, m);

    cout << "Output" << endl;

    a->outputByLevelOrder();

    a->HeapSort(m);

    BinaryTree<int> *searchTree = new BinaryTree<int>();

    for (int i = 1; i <= m; i++)

    {

        searchTree->makeSearchTree(array2[i]);

    }

    searchTree->preOrder(searchTree->root);

    cout << endl;

    searchTree->inOrder(searchTree->root);

    cout << endl;

 

    Huffman *c = new Huffman();

    c->HuffmanCode(HuffmanTree(array2, m), "");

    for (int i = 0; i < number; i++)

    {

        char symbol = 'A'+i;

        cout << symbol << ":" << huffmancode1[i];

        if (i < number-1){ cout << ","; } else { cout << endl; }

    }

    cout << "End" << endl;

    system("pause");

    return 0;

}

实验七 图的操作

1.实验内容(题目内容,输入要求,输出要求)

  1. 创建图类,存储结构使用邻接矩阵。
  2. 输入图的节点数n(不超过10个)、边数m,节点分别用1-n代表。
  3. 采用“起始节点,终止节点,权值”输入图的m条边,创建图。
  4. 输出从节点1开始的BFS遍历,要求小的节点在前大的在后。
  5. 输出从节点1开始的DFS遍历,要求小的节点在前大的在后。
  6. 输出从第1节点到第n节点最短路径的长度,如果没有路经,输出0。
  7. 输出最小生成树的所有边。输出格式采用“起始节点-终止节点:权值”,小的节点在前,大的节点在后,每个边独立一行输出,例如1-2:12是正确的,2-1:12是错误的。如果没有最小生成树,输出0-0:0

2.数据结构与算法描述 (整体思路描述,所需要的数据结构与算法)

  • 通过二维数组实现图的邻接矩阵表示。
  • 最短路径长度的通过实现迪克斯特拉算法求解。
  • 最小生成树通过实现Prim普林算法求解。
  • BFS广度优先遍历与之前树的层次遍历类似,通过队列实现。
  • DFS深度优先遍历与之前树的前序遍历类似,通过递归实现。

3.实现源代码

#include<iostream>

#include<queue>

#include<string>

using namespace std;

 

template<class T>

void Make2DArray(T** &x, int numberOfRows, int numberOfColumns)

{

    x = new T *[numberOfColumns];

    for (int i = 0; i < numberOfRows; i++)

    {

        x[i] = new T[numberOfColumns];

    }

}

 

template<class T>

void Delete2DArray(T ** &x, int numberOfRows)

{

    for (int i = 0; i < numberOfRows; i++)

    {

        delete[] x[i];

    }

 

    delete[] x;

    x = NULL;

}

 

template<class T>

class AdjacencyWDigraph {     //加权无向图的耗费邻接矩阵

public:

    AdjacencyWDigraph(int Vertices = 10, T noEdge = 0);

    ~AdjacencyWDigraph() { Delete2DArray(a, n + 1); }

    bool Exist(int i, int j)const;

    AdjacencyWDigraph<T>& Add(int i, int j, const T& w);

    AdjacencyWDigraph<T>& Delete(int i, int j);

    void BFS(int v, int reach[], int label);    //广度优先

    void DFS(int v, int reach[], int label);    //深度优先

    bool findPath(int v, int w,int reach[], int label);

    int findTheShortestPath(int begin, int end); //迪克斯特拉算法找最短路径

    void Prim(int n, int **c);

    int Begin(int i);

    T** getA() { return a; }    //get方法获取私有成员变量a

    int NextVertex(int i) {

        //返回下一个与i邻接的顶点

        if (i<1 || i>n) return 0;

        for (int j = pos[i] + 1; j <= n; j++)

            if (a[i][j] != NoEdge) {

                pos[i] = j;

                return j;

            }

        pos[i] = n + 1;

        return 0;

    }

private:

    T NoEdge;//用于没有边存在的情形

    int n;//顶点数目

    int e;//边数

    T **a;//二维数组

    int *pos;//记录每个顶点的邻接顶点

};

 

template<class T>

AdjacencyWDigraph<T>::AdjacencyWDigraph(int Vertices, T noEdge)

{   // 构造函数

    n = Vertices;

    e = 0;

    NoEdge = noEdge;

    Make2DArray(a, n + 1, n + 1);//程序1-13

    pos = new int[n + 1];

    for (int i = 1; i <= n; i++)

        pos[i] = 0;

    //初始化为没有边的图

        for (int i = 1; i <= n; i++)

            for (int j = 1; j <= n; j++)

                a[i][j] = NoEdge;

}

 

template<class T>

bool AdjacencyWDigraph<T>::Exist(int i, int j) const

{// 边(i, j)是否存在

    if (i<1 || j<1 || i>n || j>n || a[i][j] == NoEdge)   return false;

    return true;

}

 

template<class T>

AdjacencyWDigraph<T>& AdjacencyWDigraph<T> ::Add(int i, int j, const T& w)

{// 如果边(i,j) 不存在,则将该边加入无向图中

    if (i<1 || j<1 || i>n || j>n || i == j || a[i][j] != NoEdge)

        return *this;

    a[i][j] = w;

    a[j][i] = w;

    e++;

    return *this;

}

 

template<class T>

AdjacencyWDigraph<T>& AdjacencyWDigraph<T> ::Delete(int i, int j)

{

    / /删除边(i, j) .

        if (i<1 || j<1 || i>n || j>n || a[i][j] == NoEdge)

            return *this;

    a[i][j] = NoEdge;

    e--;

    return *this;

}

 

class OutofBounds : exception {

public:  OutofBounds() {};

};

 

template<class T>

int AdjacencyWDigraph<T>::Begin(int i) {

    //返回第一个与i邻接的顶点

    if (i<1 || i>n) throw OutofBounds();

    for (int j = 1; j <= n; j++){

        if (a[i][j] != NoEdge) {

            pos[i] = j;

            return j;

        }

    }

    pos[i] = n + 1;//没有下一个顶点

    return 0;

}

 

template<class T>

void AdjacencyWDigraph<T>::BFS(int v, int reach[], int label)

{

    //宽度优先搜索

    queue<int> Q;

    reach[v] = label;

    Q.push(v);

    cout << v << ",";

    while (!Q.empty()) {

        int w = Q.front();

        Q.pop();//获取一个已经标记的顶点

                    //对邻接的顶点进行标记

        for (int i = 1; i <= n; i++)

            if (a[w][i] != NoEdge&&reach[i] != label) {

                Q.push(i);

                cout << i;

                if (i!=n)

                {

                    cout << ",";

                }

                reach[i] = label;

            }

 

    }

}

 

template<class T>

void AdjacencyWDigraph<T>::DFS(int v, int reach[], int label)

{

    reach[v] = label;

    cout << v <<",";

    int u = Begin(v);

    while (u) {

        if (reach[u] != label)

            DFS(u, reach, label);

         u = NextVertex(v);

    }

}

 

template<class T>

bool AdjacencyWDigraph<T>::findPath(int v, int w, int reach[], int label)

{// 实际搜索v到w的路径,其中v != w.// 按深度优先方式搜索一条路径

    reach[v] = label;

    int u = Begin(v);

    while (u) {

        if (reach[u]!= label) {

            if (u == w) return true;

            if (findPath(u, w,reach, label))

                return true;

        }   u = NextVertex(v);

    }  return false;

}

 

int findMIN(int a[],int length) {

    int min = a[0];

    int positionOfMin = 0;

    for (int i = 1; i <=length; i++)

    {

        if (a[i] <= min) {

            min = a[i];

            positionOfMin = i;

        }

    }

    return  positionOfMin;

}

 

template<class T>

int AdjacencyWDigraph<T>::findTheShortestPath(int begin, int end)   //实现Dijkstra算法

{

    const int MAX = 9999;

    const int Label = 999;

    int *Dijkstra = new int [end +1];

    int weightOfPath=0;

    int positionOfMin = 0;

    for (int i = 0; i < end + 1; i++)  //初始化保存路径数组 使数据全为-1

    {

        Dijkstra[i] = MAX;

    }

 

    Dijkstra[begin] = 0;

 

    int *reach = new int [end+1];

    if (findPath(begin,end,reach, Label)) //如果存在从begin 到end 的通路

    {  

        while (Dijkstra[end] != Label)

        {

            positionOfMin = findMIN(Dijkstra, end);

            weightOfPath = Dijkstra[positionOfMin];

            Dijkstra[positionOfMin] = Label;

            for (int i = 1; i <end + 1; i++)

            {

                if (Dijkstra[i] != Label&&a[positionOfMin][i] != NoEdge&&a[positionOfMin][i] + weightOfPath < Dijkstra[i]) //如果没走过 且 其上一步走到的地方的临边存在 且 它的值加上之前走过的比直接到此处路途更短 就更新一遍表

                { 

                    Dijkstra[i] = a[positionOfMin][i] + weightOfPath;

                }

            }

 

        }

 

    }

    return weightOfPath;

}

 

template<class T>

void AdjacencyWDigraph<T>::Prim(int n, int **graph//Prim算法从节点1开始实现最小生成树

{

    int *lowcost= new int[n+1];   //以i为终点的边的最小权值当lowcost[i]=0说明以i为终点的边的最小权值=0,也就是表示i点加入了MST

    int *mst= new int[n+1];  //mst[i]:表示对应lowcost[i]的起点,即说明边<mst[i],i>是MST的一条边,当mst[i]=0表示起点i加入MST

    int i, j, min, minid;

    for (i = 2; i <= n; i++)

    {

        lowcost[i] = graph[1][i];

        if(lowcost[i]!=0)

        mst[i] = 1;

        else mst[i] = 0;

    }

    lowcost[1] = 0;

    mst[1] = 0;

 

    int begin = 1;

    int end = n;

    int *reach = new int[end + 1];

    int Label = 999;

    if (findPath(begin, end, reach, Label)) {

        for (i = 2; i <= n; i++)

        {

            min = 999999;

            minid = 0;

            for (j = 2; j <= n; j++)

            {

                if (lowcost[j] < min && lowcost[j] != 0)

                {

                    min = lowcost[j];

                    minid = j;

                }

            }

            cout << mst[minid] << "-" << minid << ":" << min << endl;

            lowcost[minid] = 0;

            for (j = 2; j <= n; j++)

            {

                if (graph[minid][j] != 0 && graph[minid][j] < lowcost[j])

                {

                    lowcost[j] = graph[minid][j];

                    mst[j] = minid;

                }

            }

        }

    }

    else

    {

        cout <<"0-0"<< ":" << "0" << endl;

    }

}

 

int main(){

    cout << "Input" << endl;

    int point;

    int edge;

    cin >> point;

    if (cin.get()==',')

    {

        cin >> edge;

    }

    AdjacencyWDigraph<int> gragh(point, 0);     //初始化一个无边图

 

    int start, end, weight;

    for (int i = 1; i <= edge; i++)

    {

        cin >> start;

        if (cin.get()==',')

        {

            cin >> end;

        }

        if (cin.get()==',')

        {

            cin >> weight;

        }

        gragh.Add(start, end, weight);

    }

    cout << "Output" << endl;

    int Label = 9;   //定义reach数组中走过的点标记为9

    int *reach = new int [point+1];

    gragh.BFS(1, reach, Label);

    cout << endl;

    int *reach2 = new int[point + 1];

    gragh.DFS(1, reach2, Label);

    cout << endl;

    cout << gragh.findTheShortestPath(1, point)<<endl;

    gragh.Prim(point, gragh.getA());

    cout << "End" << endl;

    system("pause");

}

猜你喜欢

转载自blog.csdn.net/qq_37950762/article/details/82919371