【期末代码汇总】

/*波兰表达式求值*/
#include<iostream>
#include<string.h>
#include<stack>
#include<stdlib.h>
using namespace std;
const int MAX = 20;
//计算
double calc(double num1, double num2, char op)
{
	switch (op)
	{
	case'+': return num1 + num2;
	case'-': return num1 - num2;
	case'*': return num1 * num2;
	case'/': return num1 / num2;
	}
}
int main()
{
	char str[100]; //接收输入的字符串
	char eqution[50][10]; //放算式的字符串数组
	stack<double> oprand; //数字栈
	cin.getline(str, 100);
	//切割字符串,利用字符串的空格切割
	char* p;
	int index = 0;
	p = strtok(str, " ");  //分割
	while (p)
	{
		strcpy(eqution[index++], p);  //保存分割后的字符串到eqution中
		p = strtok(NULL, " ");
	}
	index--;
	while (index >= 0) //逆序访问
	{
		if (!strcmp(eqution[index], "+") || !strcmp(eqution[index], "-") || !strcmp(eqution[index], "*") || !strcmp(eqution[index], "/")) //如果是运算符,弹出两个数字计算
		{
			double num1 = oprand.top();
			oprand.pop();
			double num2 = oprand.top();
			oprand.pop();
			oprand.push(calc(num1, num2, eqution[index][0]));
		}
		else //数字入栈
		{
			double num = strtod(eqution[index], (char**)NULL); //将数字字符串转换为数值
			oprand.push(num);
		}
		index--;
	}
	printf("%f\n", oprand.top());
	return 0;
}

/*逆波兰表达式求值*/
#include <iostream>
#include <stack>
#include <string>
using namespace std;

int main()
{
    string str;
    getline(cin, str); //输入波兰表达式的字符串(含有空格,后续进行处理
    stack<float> s;    //数字栈
    float a = 0, b = 0, temp = 0, c = 0;
    for (int i = 0; i < (int)str.size(); i++)
    {
        if (str[i] == ' ') //当遇到空格时跳过
        {
            continue;
        }
        //如果当前字符是运算符,就从数字栈中取数运算
        else if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')
        {
            if (!s.empty()) //保证栈不为空
            {
                a = s.top(); //取栈顶元素
                s.pop();     //别忘了弹出
            }
            if (!s.empty())  //取两次
            {
                b = s.top();
                s.pop();
            }
            switch (str[i])  //对当前运算符分类处理
            {
            case '+':
                s.push(a + b);
                break;
            case '-':
                s.push(b - a); //注意这里不是a-b
                break;
            case '*':
                s.push(a * b);
                break;
            case '/':
                s.push(b / a); //注意这里不是a/b
                break;
            }

        }
        //如果当前字符是数字字符,需要转换成数字
        else if (str[i] >= '0' && str[i] <= '9')
        {
            c = c * 10 + str[i] - '0'; //考虑多位数的情况,需要算出多位数

            if (str[i + 1] == ' ' || str[i + 1] == '\0') //当遇到空格,说明该数字已经取完
            {
                s.push(c);  //入栈
                c = 0;      //赋空,以便下一次运算
            }
        }
    }

    cout << s.top(); //取栈顶元素即为所求
    return 0;
}


/*利用堆栈判断一个字符串是否是回文*/
//使用堆栈判断回文
#include<iostream>
const int MAX_SIZE = 100;
using namespace std;
class Stack
{
private:
    char* data;
    int size;
    int top;
public:
    Stack()
    {
        top = -1;
        size = MAX_SIZE;
        data = new char[size];
    }
    Stack(int s)
    {
        top = -1;
        size = s;
        data = new char[size];
    }
    ~Stack()
    {
        delete[] data;
    }
    void Push(char c)
    {
        if (!isFull())
            data[++top] = c;
        else
            cout << "堆栈已满,不能压入" << endl;
    }
    void Pop()
    {
        if (!isEmpty())
            top--;
        else
            cout << "堆栈为空,不能弹出" << endl;
    }
    char getTop()
    {
        if (!isEmpty())
            return data[top];
        else
            return 0;
    }
    bool isEmpty()
    {
        if (top == -1)
            return true;
        else
            return false;
    }
    bool isFull()
    {
        if (top == MAX_SIZE - 1)
            return true;
        else
            return false;
    }

};
int main()
{
    Stack P;
    int flag = 0;
    cout << "请输入要判断的字符串:" << endl;
    string s;  //输入字符串
    cin >> s;
    int len = s.size();
    int len1;
    if (len == 1)
    {
        cout << "Yes" << endl;
        return 0;
    }
    else
    {
        for (int i = 0; i < len / 2; i++)   //压入一半字符
        {
            P.Push(s[i]);
        }
        if (len % 2 == 1)
            len1 = len + 1;
        else
            len1 = len;       //这段代码是为了保证从后半段字符与前半段对称的地方开始比较
        for (int i = len1 / 2; i < len; i++)
        {
            char ch = P.getTop();
            if (ch == s[i])
                flag = 1;
            else
                flag = 0;
            P.Pop();
        }
        if (flag)
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
    return 0;
}

/*kmp字符串模式匹配*/
#include<iostream>
#include<string>
using namespace std;
//求next数组
void getNext(string T, int* next)
{
    int j = -1, i = 0;
    next[0] = -1;
    while (i < T.length())
    {
        if (j == -1 || T[i] == T[j])
        {
            i++;
            j++;
            next[i] = j;
        }
        else
            j = next[j];
    }
}
//kmp的实现,返回值为子串在母串的位置
int kmp(string s, string t)
{
    int i = 0, j = 0;
    int lens = s.length();
    int lent = t.length();
    int next[lent + 1] = { 0 };         //定义大小的时候要比子串的长度更大,防止溢出
    getNext(t, next);
    while (i < lens && j < lent)
    {
        if (s[i] == t[j])
        {
            j++;
            i++;
        }
        else if (next[j] == -1)
        {
            i++;
        }
        else
        {
            j = next[j];
        }
    }
    if (j == lent)
        return i - j;
    else
        return -1;
}
int main()
{
    string s, t;
    cout << "输入母串";
    cin >> s;
    cout << "输入子串";
    cin >> t;
    int index = kmp(s, t);
    if (index == -1)
        cout << "子串不在母串中";
    else
        cout << "子串在母串中的位置是" << index + 1;
    return 0;
}
/*kmp多次匹配*/
#include<iostream>
#include<string>
using namespace std;

//求next数组
void getNext(string T, int* next)
{
    int j = -1, i = 0;
    next[0] = -1;
    int lenT = T.length();
    while (i < lenT)
    {
        if (j == -1 || T[i] == T[j])
        {
            i++;
            j++;
            next[i] = j;
        }
        else
            j = next[j];
    }
}
bool kmp(string s, string t)
{
    int i = 0, j = 0;
    bool flag = false;
    int lens = s.length();
    int lent = t.length();
    int next[lent + 1] = { 0 };
    getNext(t, next);
    while (i < lens) {
        while (i < lens && j < lent)
        {
            if (s[i] == t[j])
            {
                j++;
                i++;
            }
            else if (next[j] == -1)
            {
                i++;
            }
            else
            {
                j = next[j];
            }
            if (j == lent)
            {
                cout << i - lent + 1 << endl;        //如果在母串中找到了就输出位置
                flag = true;
                j = next[j];                   //回溯开始下一轮查找
            }
        }
        if (j != lent && flag == false)             //没找到,flag一直为假
            return flag;
    }
    return flag;
}
int main()
{
    string s, t;
    // cout<<"输入母串";
    cin >> s;
    // cout<<"输入子串";
    cin >> t;
    bool flag = kmp(s, t);
    if (!flag)
        cout << "-1";
    return 0;
}
/*kmp计算重复序列*/
#include <iostream>
#include <string>

using namespace std;

void getNext(string T, int* next)
{
    int j = -1, i = 0;
    next[0] = -1;
    int lenT = T.length();
    while (i < lenT)
    {
        if (j == -1 || T[i] == T[j])
        {
            i++;
            j++;
            next[i] = j;
        }
        else
            j = next[j];
    }
}

int countRepeatedSubstrings(string s) {
    int len = s.size();
    int next[len + 1] = { 0 };
    getNext(s, next);
    if (len % (len - next[len]) == 0) {
        return len / (len - next[len]);
    }
    return 1;
}

int main() {
    string s;
    getline(cin, s);
    int count = 0;
    for (int i = 0; i < s.length(); i++)
    {
        if (s[i] != ' ' && s[i] != '\n')
            count++;
    }

    if (count == 0)
        return 0;//如果输入为空,则没有输出
    cout << countRepeatedSubstrings(s) << endl;
    return 0;
}


/*将一棵以二叉链表存储的二叉树按顺序方式存储到一维数组中*/
#include<iostream>
#include<stdio.h>
using namespace std;
const int QS = 100;
struct BiNode
{
    char data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};
//定义能存放树的结点和编号的结构体
struct NodeNum
{
    BiNode* node;
    int number;
};

class BiTree
{
private:
    BiNode* root;              //指向根结点的头指针

public:
    BiTree()
    {
        root = creat(root);//调函数构建二叉树
    }
    ~BiTree()
    {
    }
    BiNode* getRoot()
    {
        return root;
    }
    BiNode* creat(BiNode* bt); //构造函数调用
    void release(BiNode* bt);  //析构函数调用,释放树的存储空间
    void toArray(char biTreeArray[], int length, int* count);//后序遍历函数调用
};

//前序构建二叉树
BiNode* BiTree::creat(BiNode* bt)
{
    char ch;
    cin >> ch;
    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new BiNode;
        bt->data = ch;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);
    }
    return bt;
}

//析构函数
void BiTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        delete bt;
    }
}

//将二叉树存储到一维数组中
void BiTree::toArray(char biTreeArray[], int length, int* count)
{

    int front = -1, rear = -1;        //采用顺序队列,并假定不会溢出
    int num;                             //用来控制二叉数组的下标
    NodeNum Q[QS];           //定义队列
    NodeNum nodenum;     //临时变量
    BiNode* p;                       //指向当前处理的树结点
    //数组的初始化
    for (int i = 0; i < length; i++)
    {
        biTreeArray[i] = 0;
    }

    if (root == NULL)                //二叉树为空,算法结束
    {
        return;
    }
    nodenum.node = root;
    nodenum.number = 1;     //根结点编号为1,存入数组时,需在编号基础上减1
    Q[++rear] = nodenum;
    //当队列非空时,进行层序遍历
    while (front != rear)
    {
        nodenum = Q[++front]; //出队
        //当前结点值存入临时变量,并将出队的结点存入二叉树组
        p = nodenum.node;       //p指向当前结点
        num = nodenum.number; //获取树结点编号
        biTreeArray[num - 1] = nodenum.node->data;  //存入数组
        //如果有左孩子,则左孩子入队
        if (p->lchild != NULL)
        {
            nodenum.node = p->lchild;
            nodenum.number = 2 * num;   //计算编号
            Q[++rear] = nodenum;           //左孩子入队
            *count = nodenum.number; //count记录字符串最大的存储序号
        }
        //如果有右孩子,则右孩子入队
        if (p->rchild != NULL)
        {
            nodenum.node = p->rchild;
            nodenum.number = 2 * num + 1;//根结点为n=1,存入数组时,在编号基础上减1
            Q[++rear] = nodenum;             //右孩子入队
            *count = nodenum.number;   //count记录字符串最大的存储序号
        }
    }
}

//输出一维数组
void print(char BiTreeArray[], int length)
{
    for (int i = 0; i < length; i++)
    {
        if (BiTreeArray[i])
            cout << BiTreeArray[i];
        else
            cout << "^";
    }
}
int main()
{
    int count = 0;   //记录字符串最大存储序号
    cout << "输入前序字符串:";
    BiTree tree;
    char biTreeArray[1000] = { 0 };
    tree.toArray(biTreeArray, 1000, &count);
    print(biTreeArray, count);
    return 0;
}
/*将一棵用层序输入存储到一维数组的二叉树以前序遍历的方式输出*/
#include<iostream>
using namespace std;
const int SIZE = 10000;


struct BiNode {
    char data;
    BiNode* lchild, * rchild;
};
class BiTree
{
private:
    char biTreeArray[SIZE];
    void preOrder(int bt);
public:
    BiTree();
    ~BiTree() {
    }
    void preOrder() {
        preOrder(1); //从根节点开始进行前序遍历
    }
    void release(BiNode* bt);  //析构函数调用,释放树的存储空间 
};
BiTree::BiTree()
{
    //用层序遍历法创建二叉树,输入字符串
    int i;
    for (i = 0; i < SIZE; i++) //初始化
    {
        biTreeArray[i] = 0;
    }
    cin >> biTreeArray;
}

void BiTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        delete bt;
    }
}

void BiTree::preOrder(int bt) //bt表示当前节点在数组中的索引位置(从1开始)
{
    //如果为^或0,说明遇到空指针
    if (biTreeArray[bt - 1] == '^' || biTreeArray[bt - 1] == 0) //数组是从0开始的,所以需要bt-1
        return;
    else
    {
        cout << biTreeArray[bt - 1];
        preOrder(bt * 2); //递归查找左子树
        preOrder(bt * 2 + 1); //递归查找右子树
        //对于一棵具有n个结点的完全二叉树的结点从1开始层序编号,则对于任意的编号为i的结点,其左孩子编号为2i,右孩子编号为2i+1
    }
}
int main() {
    BiTree tree;
    tree.preOrder();
    return 0;
}

/*设计算法判断一棵树是否为完全二叉树*/
//借助队列用层序遍历实现
#include<iostream>
#include<queue>
using namespace std;
const int QUEUESIZE = 100;


struct BiNode {
    char data;
    BiNode* lchild, * rchild;
};
class BiTree
{
private:
    BiNode* root;
public:
    BiTree() { root = creat(root); }
    ~BiTree() {
        release(root);
    }
    BiNode* getRoot() { return root; }
    BiNode* creat(BiNode* bt); //构造函数调用
    void release(BiNode* bt);  //析构函数调用,释放树的存储空间 
    void leverOrder(BiNode* bt);//层序遍历函数调用
    bool isCompleteBiTree(BiNode* bt);//判断是否为完全二叉树
};

BiNode* BiTree::creat(BiNode* bt)
{
    char ch;
    cin >> ch;

    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new BiNode;
        bt->data = ch;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);

    }
    return bt;
}

void BiTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        // cout<<"delete "<<bt->data<<endl;
        delete bt;
    }
}
void BiTree::leverOrder(BiNode* bt)
{
    BiNode* q;
    queue<BiNode*> Q;
    Q.push(root);
    if (root == NULL)
        return;
    while (!Q.empty())
    {
        q = Q.front();
        cout << q->data;
        Q.pop();
        if (q->lchild != NULL)
            Q.push(q->lchild);
        if (q->rchild != NULL)
            Q.push(q->rchild);
    }
}
bool BiTree::isCompleteBiTree(BiNode* bt)
{
    if (bt == NULL)
        return true;
    queue<BiNode*> Q;
    Q.push(bt);
    bool flag = false;
    while (!Q.empty())
    {
        BiNode* node = Q.front();
        Q.pop();
        if (node->lchild)  //如果左孩子存在
        {
            if (flag)     //但是前面有缺失的结点
                return false; //不是完全二叉树
            else          //前面是结点是满的
                Q.push(node->lchild); //把左孩子入队
        }
        else
        {
            flag = true;  //左孩子结点缺失,为了下一次判断需要将flag定为真
        }
        if (node->rchild) //右孩子结点存在
        {
            if (flag)     //前面有缺失的结点
                return false;//不是完全二叉树
            else
                Q.push(node->rchild);//否则,右孩子入队
        }
        else
            flag = true;//右孩子结点缺失,为了下一次判断需要将flag定为真
    }
    return true;
}
int main() {
    BiTree tree;
    cout << "层序遍历:";
    tree.leverOrder(tree.getRoot());
    cout << endl;
    cout << "判断是否是完全二叉树:";
    if (tree.isCompleteBiTree(tree.getRoot()))
        cout << "是" << endl;
    else
        cout << "不是" << endl;

    return 0;
}


/*以二叉链表为存储结构,在二叉树中删除以值x为根结点的子树*/

#include<iostream>
using namespace std;

struct BiNode {
    char data;
    BiNode* lchild, * rchild;
};
class BiTree
{
private:
    BiNode* root;
    char x;
public:

    BiTree() { root = creat(root); }
    ~BiTree() {
    }
    BiNode* getRoot() { return root; }
    void searchDel(BiNode* bt, char x);//检查根结点
    void delSubTree(BiNode* bt, char x);//查找并删除结点
    void release(BiNode* bt);//释放树结点
    BiNode* creat(BiNode* bt);
    void preOrder(BiNode* bt);
    void inOrder(BiNode* bt);
    char getX() {  //输入要删除的结点
        cin >> x;
        return x;
    }
};
//创建二叉树
BiNode* BiTree::creat(BiNode* bt)
{
    char ch;
    cin >> ch;
    if (ch == '#')
    {
        bt = NULL;
    }
    else
    {
        bt = new BiNode;
        bt->data = ch;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);
    }
    return bt;
}

//检查根节点
void BiTree::searchDel(BiNode* bt, char x)
{
    if (bt == NULL)
        return;
    if (bt->data == x)//如果根节点就是要找的结点,直接release根节点,再将根节点赋为空
    {
        release(bt);
        root = NULL;
    }
    else//其他情况再调用delSubTree函数进行查找和删除
    {
        delSubTree(bt, x);
    }
}
//查找并删除结点
void BiTree::delSubTree(BiNode* bt, char x)
{
    if (bt == NULL)
        return;
    else
    {
        //左子树不为空,并且左子树就是要找的结点,删除左子树,再将左子树赋为空
        if (bt->lchild && bt->lchild->data == x)
        {
            release(bt->lchild);
            bt->lchild = NULL;
        }
        //右子树不为空,并且右子树就是要找的结点,删除右子树,再将右子树赋为空
        if (bt->rchild && bt->rchild->data == x)
        {
            release(bt->rchild);
            bt->rchild = NULL;
        }
        //继续递归查找
        delSubTree(bt->lchild, x);
        delSubTree(bt->rchild, x);

    }
}

void BiTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        delete bt;
    }
}
//前序遍历
void BiTree::preOrder(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    cout << bt->data;
    preOrder(bt->lchild);
    preOrder(bt->rchild);
}
//中序遍历
void BiTree::inOrder(BiNode* bt) {
    if (bt == NULL) {
        return;
    }
    else {
        inOrder(bt->lchild);
        cout << bt->data;
        inOrder(bt->rchild);
    }
}
int main()
{
    BiTree tree;
    tree.searchDel(tree.getRoot(), tree.getX());
    cout << "删除后……" << endl;
    cout << "前序遍历:";
    tree.preOrder(tree.getRoot());
    cout << "\n中序遍历:";
    tree.inOrder(tree.getRoot());
    return 0;

}

/*根据前序和中序遍历序列创建二叉树*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int MAX = 1000;
struct BiNode
{
    char data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};

class BiTree {
private:
    BiNode* root;
public:
    //prestr是前序输入的字符串,instr是中序输入的字符串
    BiTree(string prestr, string instr)
    {
        int lenpre = prestr.length();
        int lenin = instr.length();
        if (lenpre != lenin)root = NULL;//检查
        else
        {
            root = creat(root, prestr, instr);//创建根节点
        }
    }
    ~BiTree() {
        release(root);
    }
    BiNode* getRoot() { return root; }
    BiNode* creat(BiNode* bt, string prestr, string instr); //构造函数调用
    void release(BiNode* bt);  //析构函数调用,释放树的存储空间
    void preOrder(BiNode* bt);
    void postOrder(BiNode* bt);
    void inOrder(BiNode* bt);

};
//创建二叉树
BiNode* BiTree::creat(BiNode* bt, string prestr, string instr)//prestr是前序输入的字符串,instr是中序输入的字符串
{
    if (prestr.length() == 0 || instr.length() == 0)//检查
        return NULL;
    else
    {
        int pos;//用来记录查找的根节点的位置下标
        pos = instr.find(prestr[0]);//调用find函数在instr中查找根节点的下标并记录在pos中,
        bt = new BiNode;
        bt->data = prestr[0];//存储根节点
        string prelstr = prestr.substr(1, pos);//prelstr用来保存根节点的左子树,用substr函数将左子树找到并保存在prelstr中。因为此时根节点在prestr中的第一个位置,所以截取的时候要从第二个位置开始,也就是从下标为1的位置开始
        //pos也是要截取的字符串的长度,因为中序串的左侧都是左子树的结点,其节点个数就等于pos
        string inlstr = instr.substr(0, pos);//同理,inlstr用来保存在instr中找到的左子树,此时的根节点并不在第一个位置,所以截取的时候要从头开始找,也就是从下标为0的位置开始
        string prerstr = prestr.substr(pos + 1, prestr.length() - pos - 1);//再取右子树,因为这个是前序串嘛,前面已经把左子树和根节点都取到了,剩下的就都是右子树了,因此从根节点的后一位开始,到串结束为止都要截取,所以截取的长度是len-1-pos
        string inrstr = instr.substr(pos + 1, instr.length() - pos - 1);//同理
        bt->lchild = creat(bt->lchild, prelstr, inlstr);//已经取到左右子树了,那就递归创建呗
        bt->rchild = creat(bt->rchild, prerstr, inrstr);
        return bt;

    }
    return bt;
}

void BiTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        delete bt;
    }
}

void BiTree::preOrder(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    preOrder(bt->lchild);
    preOrder(bt->rchild);
}
void BiTree::postOrder(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    postOrder(bt->lchild);
    postOrder(bt->rchild);
    cout << bt->data;
}
void BiTree::inOrder(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    inOrder(bt->lchild);
    inOrder(bt->rchild);
}

int main()
{
    string s1, s2;
    cin >> s1 >> s2;
    BiTree tree(s1, s2);
    cout << "后序遍历:";
    tree.postOrder(tree.getRoot());//后序输出二叉树
    cout << endl;
    return 0;
}

/*线索二叉树(输入前序,输出中序并销毁二叉树)*/
#include<iostream>
#include<stdio.h>
using  namespace  std;

struct  ThreadNode
{
    char  data;
    ThreadNode* lchild, * rchild;
    int  ltag, rtag;
};

class  ThreadBiTree
{
private:
    ThreadNode* root;//指向线索链表的头指针
public:

    ThreadBiTree()  //构造函数,建立中序线索链表
    {
        root = NULL;
        root = creat(root);
        inThread(root);
    }
    ~ThreadBiTree();            //析构函数,释放各结点的存储空间
    ThreadNode* next(ThreadNode* p);    //查找p的后继
    void  inOrder();                                              //中序遍历线索链表
private:
    ThreadNode* creat(ThreadNode* bt);
    void  destroy(ThreadNode* p);  //线索化,由构造函数调用

    void inThread(ThreadNode* p); //线索化,由构造函数调用



};

//create函数创建二叉树
ThreadNode* ThreadBiTree::creat(ThreadNode* bt)
{
    //在此处填写创建线索二叉树的代码
    char ch;
    cin >> ch;
    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new ThreadNode;
        bt->data = ch;
        bt->ltag = 0;
        bt->rtag = 0;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);
    }
    return bt;

}
//实现二叉树线索化,这个函数由构造函数调用
void ThreadBiTree::inThread(ThreadNode* p)
{
    //在此处填写建立二叉树线索化的代码,注意,这个函数跟其他函数不同,它 的函数头可以修改,注意检查大括号是否匹配
    static ThreadNode* pre = NULL;//保存上一次递归遍历的结果
    if (p == NULL)
        return;
    inThread(p->lchild);
    if (p->lchild == NULL)
    {
        p->ltag = 1;
        p->lchild = pre;
    }
    if (pre != NULL && pre->rchild == NULL)
    {
        pre->rtag = 1;
        pre->rchild = p;
    }
    pre = p;
    inThread(p->rchild);
}

//查找p的后继
ThreadNode* ThreadBiTree::next(ThreadNode* p)
{
    //在此处填写next函数的代码
    ThreadNode* q;
    if (p->rtag == 1)
        q = p->rchild;
    else
    {
        q = p->rchild;
        while (q->ltag == 0)
            q = q->lchild;
    }
    return q;
}

//中序遍历线索链表
void ThreadBiTree::inOrder()
{
    //在此处填写中序遍历线索二叉树的代码
    if (root == NULL)
        return;
    ThreadNode* p = root;
    while (p->ltag == 0)
    {
        p = p->lchild;
    }
    cout << p->data;
    while (p->rchild != NULL)
    {
        p = next(p);
        cout << p->data;
    }
}

//析构函数,释放各结点的存储空间
//这个要注意,和普通的析构函数不一样   
ThreadBiTree::~ThreadBiTree()                             //卡了好久
{
    //在此处填写销毁线索二叉树的代码
    ThreadNode* p, * q;
    p = root;
    while (p->ltag == 0)
    {
        p = p->lchild;
    }
    q = p;
    while (p->rchild != NULL)
    {
        cout << "delete " << p->data << endl;
        p = next(p);
        delete q;
        q = p;
    }
    cout << "delete " << p->data << endl;
    delete p;
}


int  main()
{
    ThreadBiTree  tree;
    cout << "Inorder:";
    tree.inOrder();
    cout << endl << "Inorder  finished.  Calling  destructer..." << endl;
    return  0;
}

/*用字符串构建一棵二叉树(输入扩展二叉树的前序序列,输出中序*/
/**用前序字符串创建树*/
#include<iostream>
#include<stdio.h>
#include<string.h>
const  int  MAX = 1000;
using  namespace  std;
struct  BiNode
{
    char  data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};

class  BiTree
{
private:
    BiNode* root;                            //指向根结点的头指针

public:
    BiTree()
    {
        root = NULL;                        //无参构造函数,创建空的二叉树
    }
    BiTree(char  str[])
    {
        int  index = 0;
        root = creat(root, str, index);    //有参构造函数,利用已有的串构建二叉树
    }
    ~BiTree()
    {
        release(root);
    }
    BiNode* getRoot()
    {
        return  root;
    }
    void  setRoot(BiNode* bt)
    {
        root = bt;
    }
    BiNode* creat(BiNode* bt, char  str[], int& index);  //构造函数调用

    void  release(BiNode* bt);    //析构函数调用,释放树的存储空间
    void  inOrder(BiNode* bt);    //中序遍历函数调用
};

/**利用已有的字符串前序构建二叉树*/
BiNode* BiTree::creat(BiNode* bt, char  str[], int& index)
{
    if (str[index] == '#' || str[index] == '\0')
    {
        bt = NULL;
        if (str[index] == '\0')
        {
            index--;
        }
    }
    else
    {
        bt = new BiNode;
        bt->data = str[index];
        index++;
        bt->lchild = creat(bt->lchild, str, index);
        index++;
        bt->rchild = creat(bt->rchild, str, index);
    }
    return bt;
    //以下注释掉的是一个差不多的写法
    /*
    if(str[index]=='\0'){
    bt=NULL;}
    else if(str[index]=='#'){
    index++;
    bt=NULL;}
    else{
     bt=new BiNode;
            bt->data=str[index];
            index++;
     bt->lchild=creat(bt->lchild,str,index);
            bt->rchild=creat(bt->rchild,str,index);
        }
    return bt;
    */
}

/**后序释放二叉树节点*/
void  BiTree::release(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    else
    {
        release(bt->lchild);
        release(bt->rchild);
    }
}

/**中序遍历*/
void  BiTree::inOrder(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    else
    {
        inOrder(bt->lchild);
        cout << bt->data;
        inOrder(bt->rchild);
    }
}

int  main()
{
    //cout<<"输入前序字符串:";
    char  str[MAX];
    cin >> str;
    BiTree  tree(str);

    tree.inOrder(tree.getRoot());

    return  0;
}

/*设计算法复制一棵二叉树(给定前序,复制,输出中序)*/

/**用复制一棵树,用字符串构建树*/
#include<iostream>
#include<stdio.h>
#include<string.h>
const  int  MAX = 1000;
using  namespace  std;
struct  BiNode
{
    char  data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};

class  BiTree
{
private:
    BiNode* root;                            //指向根结点的头指针

public:
    BiTree()                //无参构造函数,创建空的二叉树
    {
        root = NULL;
    }
    BiTree(char  str[])        //有参构造函数,利用已有的串构建二叉树
    {
        int  index = 0;
        root = creat(root, str, index);
    }
    ~BiTree()
    {
        release(root);
    }
    BiNode* getRoot()                         //getter
    {
        return  root;
    }
    void  setRoot(BiNode* bt)           //setter
    {
        root = bt;
    }
    void  inOrder()
    {
        inOrder(root);
    }

private:
    BiNode* creat(BiNode* bt, char  str[], int& index);  //构造函数调用
    void  release(BiNode* bt);    //析构函数调用,释放树的存储空间
    void  inOrder(BiNode* bt);    //中序遍历函数调用
};

/**利用已有的字符串前序构建二叉树*/
BiNode* BiTree::creat(BiNode* bt, char  str[], int& index)   //跟上一个题一样
{
    if (str[index] == '#' || str[index] == '\0')
    {
        bt = NULL;
        if (str[index] == '\0')
        {
            index--;
        }
    }
    else
    {
        bt = new BiNode;
        bt->data = str[index];
        index++;
        bt->lchild = creat(bt->lchild, str, index);
        index++;
        bt->rchild = creat(bt->rchild, str, index);
    }
    return bt;
}

/**后序释放二叉树节点*/
void  BiTree::release(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    else
    {
        release(bt->lchild);
        release(bt->rchild);
    }
}

/**中序遍历*/
void  BiTree::inOrder(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    else
    {
        inOrder(bt->lchild);
        cout << bt->data;
        inOrder(bt->rchild);
    }
}

/*//------------分割线  普通函数------------------//*/

/*  复制一棵树
//  参数说明:传入源树和目的树的根节点指针
      注意,这里dest这个指针的值需要传出去,因此采用引用&,否则不能传回。
*/
void  copyTree(BiNode* source, BiNode*& dest)
{
    if (source == NULL)
    {
        dest = NULL;
        return;
    }
    dest = new BiNode;
    dest->data = source->data;
    copyTree(source->lchild, dest->lchild);
    copyTree(source->rchild, dest->rchild);
}

int  main()
{
    char  str[MAX];
    BiNode* dest = NULL, * source = NULL;    //指向两棵树的根节点的指针

    //        cout  <<  "请输入一棵树:(形式为:ABD##E##CF###)"<<endl;
    cin >> str;
    BiTree  sourceTree(str);
    source = sourceTree.getRoot();

    BiTree  destTree;      //创建一棵空树

    copyTree(source, dest);

    destTree.setRoot(dest);        //把复制后的树的指针存储到destTree类中

    cout << "Copy  Finished!" << endl;
    cout << "InOrder:";
    destTree.inOrder();

    return  0;
}

/*判断两棵二叉树是否结构相同(给定前序,构建二棵二叉树,判断是否相同)*/
/**字符串建树判断两棵二叉树是否结构相同*/
#include<iostream>
#include<stdio.h>
using  namespace  std;
struct  BiNode
{
    char  data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};

class  BiTree
{
private:
    BiNode* root;                            //指向根结点的头指针

public:
    BiTree()
    {
        root = NULL;
        root = creat(root);//调函数构建二叉树
    }
    ~BiTree()
    {
        release(root);
    }
    BiNode* getRoot()
    {
        return  root;
    }
    BiNode* creat(BiNode* bt);  //构造函数调用
    void  release(BiNode* bt);    //析构函数调用,释放树的存储空间

};
/**前序构建二叉树*/
BiNode* BiTree::creat(BiNode* bt)
{
    char  ch;
    cin >> ch;
    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new  BiNode;
        bt->data = ch;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);
    }
    return  bt;
}
/**后序释放二叉树节点*/
void  BiTree::release(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    else
    {
        release(bt->lchild);
        release(bt->rchild);
    }
}
/*
    isSameStructure函数
    功能:接收两棵树的根节点指针,用来判断两棵树的结构是否相同
*/
bool  isSameStructure(BiNode* bt1, BiNode* bt2)
{

    if (bt1 == NULL && bt2 == NULL)
    {
        return true;
    }
    if (bt1 == NULL || bt2 == NULL)
    {
        return false;
    }
    return isSameStructure(bt1->lchild, bt2->lchild) && isSameStructure(bt1->rchild, bt2->rchild);  //这里分开写更好看
    //bool left=isSameStructure(bt1->lchild, bt2->lchild) ;
    //bool right=isSameStructure(bt1->rchild, bt2->rchild);
    //return (left&&right);
}

int  main()
{
    BiNode* root1, * root2;

    BiTree  tree1;
    root1 = tree1.getRoot();
    BiTree  tree2;
    root2 = tree2.getRoot();

    if (isSameStructure(root1, root2))
    {
        cout << "Same  structure." << endl;
    }
    else
    {
        cout << "Different  structure." << endl;
    }

    return  0;
}

/*哈夫曼编码*/
#include<iostream>
#include<string.h>
#include <iomanip>
#define UNCONSTRUCTED -1 //表示结点没有构建树
#define MAX 20
using namespace std;
/**哈夫曼树结点结构*/
struct HTNode
{
    int weight;//结点权重
    int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标
};

/**选择最小和次小结点*/
void selectMin(HTNode* HTArray, int k, int& minIndex1, int& minIndex2);
/**创建哈夫曼树*/
void createHuffmanTree(HTNode* HTArray, int* weightArray, int leafNum);
/**打印哈夫曼树*/
//void printHufTree(HTNode* treeArray, int leafNum);




/**创建哈夫曼树
* @param HTArray为地址传递的存储哈夫曼树的数组
* @param weightArray为存储结点权重值的数组
* @param leafNum为结点个数
算法
创建一个数组,存放所有的结点。结点的个数是leafNum*2-1
将叶子结点存放到数组中,对叶子结点进行初始化
    parent,left,right设为未构建
    权重按照weightArray数组赋值
对数组中其它的结点也进行初始化
    parent,left,right设为未构建
    权重按照weightArray=0
依次求子树结点存入数组
循环本轮要填的结点的位置k位置从leafNum开始,到leafNum*2-1结束
    求最小和次小权值的下标
    minIndex1和minIndex2两个结点构建子树
        minIndex1和minIndex2的parent设为i
        第i个结点的权重为两个结点之和
        第i个结点的left为minIndex1
        第i个结点的right为minIndex2
*/
void createHuffmanTree(HTNode* HTArray, int* weightArray, int leafNum)
{
    //哈夫曼数组的长度
    int length = leafNum * 2 - 1;
    //叶子结点初始化
    for (int i = 0; i < leafNum; i++)
    {
        HTArray[i].parent = UNCONSTRUCTED;
        HTArray[i].left = UNCONSTRUCTED;
        HTArray[i].right = UNCONSTRUCTED;
        HTArray[i].weight = weightArray[i];
    }
    //非叶子结点初始化
    for (int i = leafNum; i < length; i++)
    {
        HTArray[i].parent = UNCONSTRUCTED;
        HTArray[i].left = UNCONSTRUCTED;
        HTArray[i].right = UNCONSTRUCTED;
        HTArray[i].weight = 0;//权值为0
    }

    //构建哈夫曼树
    //k为当前要写的下标,从第一个非叶子结点开始
    for (int k = leafNum; k < length; k++)
    {
        int minIndex1, minIndex2;//两个最小值的下标
        selectMin(HTArray, k, minIndex1, minIndex2);//求最小和次小权值的下标
        //cout<<"\n本轮写的结点下标k="<<k<<" minIndex1="<<minIndex1<<" minIndex2="<<minIndex2<<endl;

        //minIndex1和minIndex2两个结点构建子树
        HTArray[k].weight = HTArray[minIndex1].weight + HTArray[minIndex2].weight;
        HTArray[k].left = minIndex1;
        HTArray[k].right = minIndex2;
        HTArray[minIndex1].parent = k;
        HTArray[minIndex2].parent = k;
        //cout<<"最小下标"<<minIndex1<<"次小下标"<<minIndex2<<endl;
        //printHufTree(HTArray,leafNum);//打印中间结果
    }
    return;
}


/**选择最小和次小权重
*@param HTArray 存放哈夫曼树结点的数组
*@param k 为当前要写的结点的下标
*@param minIndex1,minIndex2最小和次小结点的下标
查找权重值最小的两个结点的思想是:从树组起始位置开始,首先找到两个无父结点的结点(说明还未使用其构建成树),然后和后续无父结点的结点依次做比较,有两种情况需要考虑:
如果比两个结点中较小的那个还小,就保留这个结点,删除原来较大的结点;
如果介于两个结点权重值之间,替换原来较大的结点;
*/
void selectMin(HTNode* HTArray, int k, int& minIndex1, int& minIndex2)
{
    int i = 0;
    minIndex1 = -1;
    minIndex2 = -1;
    while (i < k)
    {
        if (HTArray[i].parent == UNCONSTRUCTED)
        {
            if (minIndex1 == -1 || HTArray[i].weight < HTArray[minIndex1].weight)
            {
                minIndex2 = minIndex1;
                minIndex1 = i;
            }
            else if (minIndex2 == -1 || HTArray[i].weight < HTArray[minIndex2].weight)
            {
                minIndex2 = i;
            }
        }
        i++;
    }
}


/**生成哈夫曼编码的函数
HTArray 存放哈夫曼树的数组
code 存放编码的字符串
leafNum 叶子节点个数
从叶子结点一直找到根结点,逆向记录途中经过的标记。
是左儿子标记0,右儿子标记1。
*/
void huffmanCoding(HTNode* HTArray, char**& code, int leafNum)
{
    char* temp; //声明temp数组
    temp = new char[leafNum];//定义临时工作空间,存储临时产生的编码串
    temp[leafNum - 1] = '\0';  //因为是逆向,所以得从末尾开始,先把最后一位置为空
    int start, pos;  //start为temp数组正在处理位置de下标,pos记录正在处理的哈夫曼树的当前位置
    int parent;  //记录父节点
    for (int i = 0; i < leafNum; i++)//依次遍历哈夫曼数组
    {
        start = leafNum - 1;
        pos = i;
        parent = HTArray[i].parent; //找到父节点
        while (parent != -1)
        {
            if (HTArray[parent].left == pos) //当前结点是左孩子的话,就存0
            {
                temp[--start] = '0'; //start前移一位,存入编码
            }
            else //右孩子,存1
            {
                temp[--start] = '1';
            }
            pos = parent; //pos移动到父节点,以进行下一轮查找
            parent = HTArray[parent].parent;//更新父节点
        }
        code[i] = new char[leafNum - start]; //建立哈夫曼编码实际需要的内存空间
        //leafNum-start是正在处理结点的编码长度
        strcpy(code[i], &temp[start]);       //将临时存储的编码拷贝到code中
    }
    delete[]temp; //释放工作空间
}
//打印哈弗曼编码
void printCode(char** code, char* data, int leafNum)
{
    // cout<<"哈夫曼编码是\n";
    for (int i = 0; i < leafNum; i++)
    {
        cout << data[i] << ":";
        cout << code[i] << endl;
    }

}


int main()
{
    //叶子结点个数
    int leafNum;
    int i;
    int w[MAX] = { 0 };
    //权值数组和字符数组
    cin >> leafNum;
    for (i = 0; i < leafNum; i++)
    {
        cin >> w[i];
    }
    //输入字符数组
    char ch[MAX] = { 0 };
    char** code = new char* [leafNum]; //二级指针,指向指针的指针。为code分配内存空间,存储编码
    for (i = 0; i < leafNum; i++)
    {
        cin >> ch[i];
    }
    //哈夫曼树数组
    HTNode* HTArray = new HTNode[leafNum * 2 - 1];
    //创建哈夫曼树
    createHuffmanTree(HTArray, w, leafNum);
    //哈夫曼编码
    huffmanCoding(HTArray, code, leafNum);
    //打印哈夫曼编码
    printCode(code, ch, leafNum);
    //删除内存
    for (int j = 0; j < leafNum; j++)
    {
        delete code[j];
    }
    delete[]code;
    delete[]HTArray;
    return 0;
}
/*计算WPL*/

/*求哈夫曼树的权值*/
//首先找到叶子结点,然后用叶子结点的数字*其哈夫曼编码的长度,再求和
int seekWPL(HTNode* HTArray, int leafNum, char** code)
{
    int i = 0;
    int sum = 0;
    while (i < leafNum)
    {
        if (HTArray[i].left == -1 && HTArray[i].right == -1)//找到叶子结点
        {
            int length = strlen(code[i]);
            sum += HTArray[i].weight * length;
        }
        i++;
    }
    return sum;
}

/*字符串的哈夫曼编码*/
#include<iostream>
#include<string.h>
#include <iomanip>
#include<string>
#define UNCONSTRUCTED -1 //表示结点没有构建树
#define MAX 20
using namespace std;
/**哈夫曼树结点结构*/
struct HTNode
{
    int weight;//结点权重
    int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标

};

/**选择最小和次小结点*/
void selectMin(HTNode* HTArray, int k, int& minIndex1, int& minIndex2);
/**创建哈夫曼树*/
void createHuffmanTree(HTNode* HTArray, int* weightArray, int leafNum);




/**创建哈夫曼树*/
void createHuffmanTree(HTNode* HTArray, int* weightArray, int leafNum)
{
    //哈夫曼数组的长度
    int length = leafNum * 2 - 1;
    //叶子结点初始化
    for (int i = 0; i < leafNum; i++)
    {
        HTArray[i].parent = UNCONSTRUCTED;
        HTArray[i].left = UNCONSTRUCTED;
        HTArray[i].right = UNCONSTRUCTED;
        HTArray[i].weight = weightArray[i];
    }
    //非叶子结点初始化
    for (int i = leafNum; i < length; i++)
    {
        HTArray[i].parent = UNCONSTRUCTED;
        HTArray[i].left = UNCONSTRUCTED;
        HTArray[i].right = UNCONSTRUCTED;
        HTArray[i].weight = 0;//权值为0
    }

    //构建哈夫曼树
    //k为当前要写的下标,从第一个非叶子结点开始
    for (int k = leafNum; k < length; k++)
    {
        int minIndex1, minIndex2;//两个最小值的下标
        selectMin(HTArray, k, minIndex1, minIndex2);//求最小和次小权值的下标
        //cout<<"\n本轮写的结点下标k="<<k<<" minIndex1="<<minIndex1<<" minIndex2="<<minIndex2<<endl;

        //minIndex1和minIndex2两个结点构建子树
        HTArray[k].weight = HTArray[minIndex1].weight + HTArray[minIndex2].weight;
        HTArray[k].left = minIndex1;
        HTArray[k].right = minIndex2;
        HTArray[minIndex1].parent = k;
        HTArray[minIndex2].parent = k;
        //cout<<"最小下标"<<minIndex1<<"次小下标"<<minIndex2<<endl;
        //printHufTree(HTArray,leafNum);//打印中间结果

    }
    return;
}


/**选择最小和次小权重*/
void selectMin(HTNode* HTArray, int k, int& minIndex1, int& minIndex2)
{
    int i = 0;
    minIndex1 = -1;
    minIndex2 = -1;
    while (i < k)
    {
        if (HTArray[i].parent == UNCONSTRUCTED)//找无父结点的结点(未构建树的结点)
        {
            if (minIndex1 == -1 || HTArray[i].weight < HTArray[minIndex1].weight)//比最小的还小
            {
                minIndex2 = minIndex1;
                minIndex1 = i;
            }
            else if (minIndex2 == -1 || HTArray[i].weight < HTArray[minIndex2].weight)//在两者之间
            {
                minIndex2 = i;
            }
        }
        i++;
    }
}




/**生成哈夫曼编码的函数
HTArray 存放哈夫曼树的数组
code 存放编码的字符串
leafNum 叶子节点个数
从叶子结点一直找到根结点,逆向记录途中经过的标记。
是左儿子标记0,右儿子标记1。
*/
void huffmanCoding(HTNode* HTArray, char**& code, int leafNum)
{
    char* temp; //声明temp数组
    temp = new char[leafNum];//定义临时工作空间,存储临时产生的编码串
    temp[leafNum - 1] = '\0';  //因为是逆向,所以得从末尾开始,先把最后一位置为空
    int start, pos;  //start为temp数组正在处理位置de下标,pos记录正在处理的哈夫曼树的当前位置
    int parent;  //记录父节点
    for (int i = 0; i < leafNum; i++)//依次遍历哈夫曼数组
    {
        start = leafNum - 1;
        pos = i;
        parent = HTArray[i].parent; //找到父节点
        while (parent != -1)
        {
            if (HTArray[parent].left == pos) //当前结点是左孩子的话,就存0
            {
                temp[--start] = '0'; //start前移一位,存入编码
            }
            else //右孩子,存1
            {
                temp[--start] = '1';
            }
            pos = parent; //pos移动到父节点,以进行下一轮查找
            parent = HTArray[parent].parent;//更新父节点
        }
        code[i] = new char[leafNum - start]; //建立哈夫曼编码实际需要的内存空间
        //leafNum-start是正在处理结点的编码长度
        strcpy(code[i], &temp[start]);       //将临时存储的编码拷贝到code中    
    }
    delete[]temp; //释放工作空间
}
//打印编码
void printCode(HTNode* HTArray, char** code, char* data, int leafNum)
{
    // cout<<"哈夫曼编码是\n";
    for (int i = 0; i < leafNum; i++)
    {
        cout << data[i] << ":";
        cout << code[i] << endl;
    }

}

int main()
{
    string s;
    int i;
    int word[27] = { 0 };//记录从a到z的每个字母的个数
    getline(cin, s); //获取带空格的字符串
    //计算字母个数
    for (i = 0; i < s.length(); i++)
    {
        if (isalpha(s[i])) //判断当前字符是否是字母
        {
            s[i] = tolower(s[i]); //如果是的话,将大写转换成小写
            word[s[i] - 'a']++; //记录个数
        }

    }
    int count = 0;// 计算有多少个字母个数不为0
    for (i = 0; i < 26; i++)
    {
        if (word[i] != 0)
            count++;
    }
    int weightArray[27] = { 0 };
    char data[27] = { 0 }; //记录实际个数不为0的字母
    int j = 0;
    for (i = 0; i < 26; i++)
    {
        if (word[i] != 0)
        {
            weightArray[j] = word[i];
            data[j] = 'A' + i;
            j++;
        }
    }
    char** code = new char* [count]; //为code分配内存空间,存储编码

    //哈夫曼树数组
    HTNode* HTArray = new HTNode[count * 2 - 1];
    //创建哈夫曼树
    createHuffmanTree(HTArray, weightArray, count);

    //生成哈夫曼编码
    huffmanCoding(HTArray, code, count);

    //打印编码
    printCode(HTArray, code, data, count);

    //删除内存
    for (int j = 0; j < count; j++)
    {
        delete code[j];
    }
    delete[]code;
    delete[]HTArray;
    return 0;
}

/*使用邻接矩阵存储无向图*/
 /**使用邻接矩阵存储--无向图*/
#include<iostream>
#include<limits.h>
#define MAX_V_NUM 20  //顶点的最大个数
using namespace std;
/**图类*/
template <class T>
class MGraph
{
private:
    T vertex[MAX_V_NUM];//图元素的一维数组
    int arc[MAX_V_NUM][MAX_V_NUM];//图的邻接矩阵,二维数组
    int vexNum, arcNum;//元素个数,边的个数
public:

    MGraph()
    {
        cin >> vexNum;
        int i, j;
        for (i = 0; i < vexNum; i++)
        {
            cin >> vertex[i];//图元素的一维数组
        }
        for (i = 0; i < vexNum; i++)
            for (j = 0; j < vexNum; j++)
                arc[i][j] = 0;//初始化邻接矩阵
        cin >> arcNum;
        for (i = 0; i < arcNum; i++)
        {
            int start, endi;
            cin >> start >> endi;
            arc[start][endi] = 1;//对称矩阵
            arc[endi][start] = 1;
        }
    }
    ~MGraph() {};
    void DFSTraverse(int v);
    void BFSTraverse(int v);
    void printMG()
    {
        cout << "图的顶点有:";
        int i, j;
        for (i = 0; i < vexNum; i++)
        {
            cout << vertex[i] << " ";
        }
        cout << endl;
        cout << "图的边有:";
        for (i = 0; i < vexNum; i++)//
        {
            for (j = i + 1; j < vexNum; j++)//
            {
                if (arc[i][j] == 1)
                {
                    cout << vertex[i] << "-" << vertex[j] << " ";
                }
            }
        }
        cout << endl;
    }
    int computeArcNum();//计算边的条数
    bool isConnected(T v1, T v2);//判断两个顶点是否有边相连
    int getIndex(T vertex);//获得顶点的下标
    int getDegree(T vertex);//求顶点的度

};

template <class T>
/**计算边的条数*/
int MGraph<T>::computeArcNum()
{
    int count = 0;
    int i, j;
    for (i = 0; i < vexNum; i++)
    {
        for (j = 0; j < vexNum; j++)
        {
            if (arc[i][j] == 1)
                count++;
        }
    }
    return count / 2;
}

template <class T>
/**获取对应值的下标*/
int MGraph<T>::getIndex(T vertex1)
{
    int i;
    for (i = 0; i < vexNum; i++)
    {
        if (vertex[i] == vertex1)
        {
            return i;
        }
    }
    return -1;//找不到对应的顶点
}

template <class T>
/** 判断两个顶点是否连接 */
bool MGraph<T>::isConnected(T v1, T v2)
{
    int index1 = getIndex(v1);
    int index2 = getIndex(v2);
    if (index1 == -1 || index2 == -1)
    {
        return false;//如果有一个顶点不存在,返回false
    }
    return arc[index1][index2] == 1;//根据邻接矩阵判断两个顶点是否相连
}

template <class T>
/**求顶点的度*/
int MGraph<T>::getDegree(T vertex)//求度
{
    int i;
    int index = getIndex(vertex);
    if (index == -1)
    {
        return -1;
    }
    int degree = 0;
    for (i = 0; i < vexNum; i++)
    {
        if (arc[index][i] == 1)
        {
            degree++;
        }
    }
    return degree;
}


int main()
{

    MGraph<char> graph;
    //graph.printMG();

    cout << "The number of edges: " << graph.computeArcNum() << endl;
    //cout<<"\n判断顶点是否相连,请输入两个顶点的值:";
    char v1, v2;
    cin >> v1 >> v2;
    if (graph.isConnected(v1, v2))
        cout << v1 << " and " << v2 << " is connected." << endl;
    else
        cout << v1 << " and " << v2 << " is not connected." << endl;
    //cout<<"输出顶点的度,输入一个顶点";
    cin >> v1;
    cout << v1 << " degree: " << graph.getDegree(v1);
    return 0;
}

/*使用邻接表存储有向网*/
#include<iostream>
#define  MAX_VERTEX_NUM 20//最大顶点个数
using namespace std;

/**边表的结构体*/
struct ArcNode
{
    int adjvex;//邻接点在数组中的位置下标
    struct ArcNode* nextArc;//指向下一个邻接点的指针
    int weight;//权值,网才有权值
};

/**顶点的结构体*/
template <class T>
struct VNode
{
    T vertex;//顶点的数据域
    ArcNode* firstArc;//指向邻接点的指针
};

/**邻接表类*/
template <class T>
class ALGraph
{
private:
    VNode<T> AdjList[MAX_VERTEX_NUM];//顶点表的数组
    int vexNum, arcNum;//记录图中顶点数和边或弧数
public:
    ALGraph();//构造函数
    ~ALGraph() {}; //析构函数
    void printALG();//打印函数
    void createDN();//构造有向网
    int getOutDegreeDN(T vertex);//根据指定的值求出度
    int getInDegreeDN(T vertex);//根据指定的值求入度
    void setVertex(int index, T value);
    void incrementVexNum();
};

template <class T>
ALGraph<T>::ALGraph() {
    // 将顶点数和边数初始化为0
    vexNum = 0;
    arcNum = 0;
    // 顶点表的数组初始化
    for (int i = 0; i < MAX_VERTEX_NUM; i++) {
        AdjList[i].firstArc = NULL;
    }
}
// 输出函数
template <class T>
void ALGraph<T>::printALG() {
    cout << "图的顶点有:";
    // 依次遍历顶点表,输出顶点
    for (int i = 0; i < vexNum; i++) {
        cout << AdjList[i].vertex << " ";
    }
    cout << endl;
    // 遍历边表
    cout << "图的边有:";
    for (int i = 0; i < vexNum; i++) {
        ArcNode* p = AdjList[i].firstArc; //定义一个p指针,初始化指向顶点表的第一个指向邻接表的指针
        // 遍历边表,p不为空的话
        while (p) {
            cout << AdjList[i].vertex << "-" << AdjList[p->adjvex].vertex << ":[" << p->weight << "] ";  //就输出边表对应的数据:起始位置-终点位置:【权值】
            p = p->nextArc; //p移到下一位
        }
    }
    cout << endl;
}
// 构建有向图
template <class T>
void ALGraph<T>::createDN() {
    int u, v, w;
    // 输入起点下标,终点下标,权值
    cin >> u >> v >> w;
    ArcNode* p = new ArcNode; //定义邻接表的p指针
    p->adjvex = v; //传入邻接点在数组中的终点位置下标
    p->weight = w; //传入对应的权值
    // 头插法插入新的数据
    p->nextArc = AdjList[u].firstArc;
    AdjList[u].firstArc = p;
    arcNum++; //边数增加
}
//获取顶点的下标
template <class T>
int ALGraph<T>::getIndex(T vertex) { //传入顶点
    for (int i = 0; i < vexNum; i++) { //遍历顶点表
        if (AdjList[i].vertex == vertex) { //如果顶点表的数据域与传入要查找的顶点相同的话,就返回此时的下标
            return i;
        }
    }
    return -1; //如果没找到,就返回-1
}
//根据指定的值求出度
template <class T>
int ALGraph<T>::getOutDegreeDN(T vertex) {
    int index = getIndex(vertex);
    if (index == -1) { //如果传入的数据不属于顶点表,就返回-1
        return -1;
    }
    int count = 0;
    ArcNode* p = AdjList[index].firstArc;
    while (p) {
        count++;
        p = p->nextArc;
    }
    return count;
}
//根据值求入度
template <class T>
int ALGraph<T>::getInDegreeDN(T vertex) {
    int count = 0;
    for (int i = 0; i < vexNum; i++) {
        ArcNode* p = AdjList[i].firstArc;
        while (p) {
            if (p->adjvex == getIndex(vertex)) {
                count++;
            }
            p = p->nextArc;
        }
    }
    return count;
}
//计算边的条数
template <class T>
int ALGraph<T>::computeArcNum() {
    int count = 0;
    //遍历边表
    for (int i = 0; i < vexNum; i++) {
        ArcNode* p = AdjList[i].firstArc;
        while (p) {
            count++;
            p = p->nextArc;
        }
    }
    return count;
}
//判断两个顶点是否有边相连
template <class T>
bool ALGraph<T>::isConnected(T v1, T v2) {
    //获取两个顶点的下标
    int index1 = getIndex(v1);
    int index2 = getIndex(v2);
    if (index1 == -1 || index2 == -1) {
        return false; //如果没找到该顶点,就返回假
    }
    //遍历下标为index1的顶点对应的边表
    ArcNode* p = AdjList[index1].firstArc;
    while (p) {
        if (p->adjvex == index2) { //邻接点在数组中的位置下标等于要找的顶点在数组中的下标,说明能找到这个顶点,所以两个顶点有关联,返回真
            return true;
        }
        p = p->nextArc;
    }
    return false;
}

//更改顶点表的数据域,传入下标和数据
template <class T>
void ALGraph<T>::setVertex(int index, T value) {
    if (index >= 0 && index < MAX_VERTEX_NUM) {
        AdjList[index].vertex = value;
    }
}
//vexNum为私有属性,不能直接访问
template <class T>
void ALGraph<T>::incrementVexNum() {
    if (vexNum < MAX_VERTEX_NUM) {
        vexNum++;
    }
}
int main() {
    ALGraph<char> graph;
    int n, m;
    // 输入顶点的个数
    cin >> n;
    // 输入顶点
    for (int i = 0; i < n; i++) {
        char v;
        cin >> v;
        graph.setVertex(i, v);
        graph.incrementVexNum();
    }
    // 输入边的个数
    cin >> m;
    // 输入边的起点下标,终点下标和权值。
    for (int i = 0; i < m; i++) {
        graph.createDN();
    }
    // 打印输出
    graph.printALG();
    return 0;
}

/*用邻接矩阵实现无向图(深度遍历、广度遍历)*/
/**使用邻接矩阵存储图
无向图
*/
#include<iostream>
#include<limits.h>
#define MAX_V_NUM 20  //顶点的最大个数
using namespace std;

/**图类*/
template <class T>
class MGraph
{
private:
    T vertex[MAX_V_NUM];//图元素的一维数组
    int arc[MAX_V_NUM][MAX_V_NUM];//图的邻接矩阵,二维数组
    int vexNum, arcNum;//元素个数,边的个数
public:
    MGraph()//构造函数,根据类型创建邻接矩阵
    {
        cin >> vexNum;
        for (int i = 0; i < vexNum; i++)
        {
            cin >> vertex[i];  //输入图元素的一维数组
        }
        for (int i = 0; i < vexNum; i++)
        {
            for (int j = 0; j < vexNum; j++)
                arc[i][j] = 0;
        }
        cin >> arcNum;
        for (int i = 0; i < arcNum; i++)
        {
            int start, end;
            cin >> start >> end;
            arc[start][end] = 1;
            arc[end][start] = 1;
        }
    }
    ~MGraph() {};
    void DFSTraverse(int v);//深度遍历
    void BFSTraverse(int v);//广度遍历
    int getIndex(T vertex1);//获得指定顶点的下标
};

//深度遍历,递归
template <class T>
void MGraph<T>::DFSTraverse(int v)
{
    static int visited[MAX_V_NUM] = { 0 }; //定义为静态数组
    cout << vertex[v] << " ";
    visited[v] = 1;
    for (int j = 0; j < vexNum; j++)
    {
        if (arc[v][j] == 1 && visited[j] == 0) //有边并且没被访问过
        {
            DFSTraverse(j);
        }
    }
}

//广度遍历,队列
template <class T>
void MGraph<T>::BFSTraverse(int v)
{
    bool visited[MAX_V_NUM] = { false }; // 标记顶点是否被访问过
    int queue[MAX_V_NUM]; // 用于存储待访问的顶点
    int front = 0, rear = 0;

    visited[v] = true;
    cout << vertex[v] << " ";
    queue[rear++] = v;

    while (front != rear)
    {
        int cur = queue[front++];
        for (int i = 0; i < vexNum; i++)
        {
            if (arc[cur][i] == 1 && !visited[i])
            {
                visited[i] = true;
                cout << vertex[i] << " ";
                queue[rear++] = i;
            }
        }
    }
}

template <class T>
/**获取对应值的下标*/
int MGraph<T>::getIndex(T vertex1)
{
    int i;
    for (i = 0; i < vexNum; i++)
    {
        if (vertex[i] == vertex1)
        {
            return i;
        }
    }
    return -1;//找不到对应的顶点
}


int main()
{

    MGraph<char> graph;
    //graph.printMG();
    //graph.printMatrix();
    char v;
    //cout<<"\n请输入遍历的起始顶点";
    cin >> v;

    cout << "-----------------\n深度优先遍历的结果:";
    graph.DFSTraverse(graph.getIndex(v));
    cout << "\n-----------------\n广度优先遍历的结果:";
    graph.BFSTraverse(graph.getIndex(v));
    //cout<<"\n-----------------\n"<<v<<"的度:"<<graph.getDegree(v);

    return 0;
}

/*用邻接表实现有向网(深度遍历、广度遍历)*/
/**邻接表表示有向网*/
#include<iostream>
#include<queue>
#define  MAX_V_NUM 20//最大顶点个数
using namespace std;
/**边表的结构体*/
struct ArcNode
{
    int adjvex;//邻接点在数组中的位置下标
    struct ArcNode* nextArc;//指向下一个邻接点的指针
    int weight;//权值,网才有权值
};
/**顶点的结构体*/
template <class T>
struct VNode
{
    T vertex;//顶点的数据域
    ArcNode* firstArc;//指向邻接点的指针
};
/**邻接表类*/
template <class T>
class ALGraph
{
private:
    VNode<T> AdjList[MAX_V_NUM];//顶点表的数组
    int vexNum, arcNum;//记录图中顶点数和边或弧数
    bool visited[MAX_V_NUM] = { false }; // 定义visited数组
public:
    ALGraph();//构造函数
    ~ALGraph() {}; //析构函数
    int getIndex(T vertex);//获得顶点的下标
    void DFSTraverse(int v);
    void BFSTraverse(int v);
    void createDN();//构造有向网
    void setVertex(int index, T value);
    void incrementVexNum();
};

template <class T>
ALGraph<T>::ALGraph() {
    // 将顶点数和边数初始化为0
    vexNum = 0;
    arcNum = 0;
    // 顶点表的数组初始化
    for (int i = 0; i < MAX_V_NUM; i++) {
        AdjList[i].firstArc = NULL;
    }
}

// 构建有向图
template <class T>
void ALGraph<T>::createDN() {
    int u, v, w;
    // 输入起点下标,终点下标,权值
    cin >> u >> v >> w;
    ArcNode* p = new ArcNode; //定义邻接表的p指针
    p->adjvex = v; //传入邻接点在数组中的终点位置下标
    p->weight = w; //传入对应的权值
    // 头插法插入新的数据
    p->nextArc = AdjList[u].firstArc;
    AdjList[u].firstArc = p;
    arcNum++; //边数增加
}

template <class T>
void ALGraph<T>::DFSTraverse(int v) {
    visited[v] = true;
    cout << AdjList[v].vertex << " ";
    for (ArcNode* p = AdjList[v].firstArc; p != NULL; p = p->nextArc) {
        int w = p->adjvex;
        if (!visited[w]) {
            DFSTraverse(w);
        }
    }
}

//广度遍历
template <class T>
void ALGraph<T>::BFSTraverse(int v) {
    queue<int> q;
    //visited数组进行初始化
    for (int i = 0; i < vexNum; i++)
    {
        visited[i] = false;
    }
    visited[v] = true;
    q.push(v);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        cout << AdjList[u].vertex << " ";
        ArcNode* p = AdjList[u].firstArc;
        while (p != NULL)
        {
            if (!visited[p->adjvex])//判断顶点是否被访问过,没有的话就进入队列,把它的visited值设置为已访问
            {
                q.push(p->adjvex);
                visited[p->adjvex] = true;
            }
            p = p->nextArc;//指向下一个结点
        }

    }
}

//获取顶点的下标
template <class T>
int ALGraph<T>::getIndex(T vertex) { //传入顶点
    for (int i = 0; i < vexNum; i++) { //遍历顶点表
        if (AdjList[i].vertex == vertex) { //如果顶点表的数据域与传入要查找的顶点相同的话,就返回此时的下标
            return i;
        }
    }
    return -1; //如果没找到,就返回-1
}
//更改顶点表的数据域,传入下标和数据
template <class T>
void ALGraph<T>::setVertex(int index, T value) {
    if (index >= 0 && index < MAX_V_NUM) {
        AdjList[index].vertex = value;
    }
}
//vexNum为私有属性,不能直接访问
template <class T>
void ALGraph<T>::incrementVexNum() {
    if (vexNum < MAX_V_NUM) {
        vexNum++;
    }
}

int main()
{
    ALGraph<char> graph;
    int n, m;
    // 输入顶点的个数
    cin >> n;
    // 输入顶点
    for (int i = 0; i < n; i++) {
        char v;
        cin >> v;
        graph.setVertex(i, v);
        graph.incrementVexNum();
    }
    // 输入边的个数
    cin >> m;
    // 输入边的起点下标,终点下标和权值。
    for (int i = 0; i < m; i++) {
        graph.createDN();
    }
    //graph.printALG();
    char v;
    //cout<<"\n请输入遍历的起始顶点";
    cin >> v;

    cout << "-----------------\n深度优先遍历的结果:";
    graph.DFSTraverse(graph.getIndex(v));
    cout << "\n-----------------\n广度优先遍历的结果:";
    graph.BFSTraverse(graph.getIndex(v));
    return 0;
}

/*Floyd算法*/
#include<iostream>
#include<algorithm>
#include<string>
#include<limits.h>
using namespace std;
const int MAX_V_NUM = 100;


template <class T>
class EdgeGraph
{
private:
    char vertex[MAX_V_NUM] = { 0 };  //存放图顶点的数组
    int dist[MAX_V_NUM][MAX_V_NUM] = { INT_MAX };
    string path[MAX_V_NUM][MAX_V_NUM]; //用来存放路径
    int vexNum, arcNum;         //图的顶点数和边数
public:
    EdgeGraph(int vNum, int eNum);//构造函数
    void Floyd();
    int getIndex(char v)
    {
        for (int i = 0; i < vexNum; i++) {
            if (vertex[i] == v) {
                return i;
            }
        }
        return -1; // 如果找不到顶点,返回-1
    }
    //路径拼接函数,需要将传入的a末尾和b的开头部分的重复字母处理一下,拼成新的路径。比如:a是abc,b是cde,result是abcde,重复的c只存入了一次
    string Combine(string a, string b)
    {
        if (a == b)
            return   "";
        else {
            string result;
            result.resize(a.length() + b.length()); // 预先分配足够的空间,没有分配空间就无法返回正确的字符串
            int index = 0;
            int inda = 0, indb = 0;
            while (inda < a.length()) //先将a串存入result
            {
                result[index++] = a[inda++];
            }
            indb++; //跳过b串的第一个字符
            while (indb < b.length()) //将b后面的内容存入result
            {
                result[index++] = b[indb++];
            }
            result[index] = '\0'; //结束
            return result;
        }
    }
};
template <class T>
EdgeGraph<T>::EdgeGraph(int vNum, int eNum)
{
    vexNum = vNum;
    arcNum = eNum;
    //dist数组的初始化,让对角线上为0,其余为无穷大
    for (int i = 0; i < vexNum; i++)
    {
        for (int j = 0; j < vexNum; j++)
        {
            if (i == j)
                dist[i][j] = 0;
            else
                dist[i][j] = INT_MAX;
        }
    }
    char v;
    T f, t;
    int w;
    cout << "请输入顶点的值";
    for (int i = 0; i < vexNum; i++)
    {
        cin >> v;
        vertex[i] = v;
    }

    cout << "请输入边依附的两个顶点和权值:\n";
    for (int i = 0; i < arcNum; i++)
    {
        cin >> f;
        cin >> t;
        cin >> w;
        dist[getIndex(f)][getIndex(t)] = w;
    }
}
template <class T>
void EdgeGraph<T>::Floyd()
{
    //初始化path
    for (int i = 0; i < vexNum; i++)
    {
        for (int j = 0; j < vexNum; j++)
        {
            if (dist[i][j] != INT_MAX && dist[i][j] != 0) //如果两个地点有路线连接,并且起点和终点不是同一个位置
            {
                path[i][j] = { vertex[i],vertex[j] }; //把起始位置和终点位置拼成一个字符串,存入path 中
            }
            else
                path[i][j] = "";  //否则path中存空
        }
    }

    //开始查找
    string result; //记录路径结果
    for (int k = 0; k < vexNum; k++)
    {
        for (int i = 0; i < vexNum; i++)
        {
            for (int j = 0; j < vexNum; j++)
            {
                if (dist[i][k] + dist[k][j] < dist[i][j] && dist[i][k] != INT_MAX && dist[k][j] != INT_MAX) //当找到更短的路径
                {
                    dist[i][j] = dist[i][k] + dist[k][j]; //更新短路径
                    result = Combine(path[i][k], path[k][j]);  //并记录path,存入到path数组中
                    path[i][j] = result;
                }
            }
        }
    }
    //输出
    cout << "显示每对顶点间的最短路径:" << endl;
    for (int i = 0; i < vexNum; ++i) {
        for (int j = 0; j < vexNum; ++j) {
            if (i == j)
                continue;
            else {
                if (dist[i][j] == INT_MAX) {
                    cout << "<" << vertex[i] << "," << vertex[j] << "> 无路径";
                    if (i < arcNum - 1)
                        cout << endl;
                }
                else {
                    cout << "<" << vertex[i] << "," << vertex[j] << "> 的最短路径为:" << path[i][j] << " 最短路径长度为:" << dist[i][j];
                    if (i < arcNum - 1)
                        cout << endl;
                }
            }
        }
    }
}

int main()
{
    int vNum, eNum;
    cout << "请输入顶点个数和边的个数:";
    cin >> vNum >> eNum;
    EdgeGraph<char> graph(vNum, eNum);
    graph.Floyd();
    return 0;
}
/*娱乐中心选址*/
#include<iostream>
#include<algorithm>
#include<string>
#include<limits.h>
using namespace std;
const int MAX_V_NUM = 100;


template <class T>
class EdgeGraph
{
private:
    char vertex[MAX_V_NUM] = { 0 };  //存放图顶点的数组
    int dist[MAX_V_NUM][MAX_V_NUM] = { INT_MAX };
    string path[MAX_V_NUM][MAX_V_NUM]; //用来存放路径
    int vexNum, arcNum;         //图的顶点数和边数
    int shortP[MAX_V_NUM];
    int newdist[MAX_V_NUM][MAX_V_NUM];
public:
    EdgeGraph(int vNum, int eNum);//构造函数
    void Floyd();
    void getShortPath();  //存储每对顶点的最短路径
    int getIndex(char v)
    {
        for (int i = 0; i < vexNum; i++) {
            if (vertex[i] == v) {
                return i;
            }
        }
        return -1; // 如果找不到顶点,返回-1
    }
    //路径拼接函数,需要将传入的a末尾和b的开头部分的重复字母处理一下,拼成新的路径。比如:a是abc,b是cde,result是abcde,重复的c只存入了一次
    string Combine(string a, string b)
    {
        if (a == b)
            return   "";
        else {
            string result;
            result.resize(a.length() + b.length()); // 预先分配足够的空间,没有分配空间就无法返回正确的字符串
            int index = 0;
            int inda = 0, indb = 0;
            while (inda < a.length()) //先将a串存入result
            {
                result[index++] = a[inda++];
            }
            indb++; //跳过b串的第一个字符
            while (indb < b.length()) //将b后面的内容存入result
            {
                result[index++] = b[indb++];
            }
            result[index] = '\0'; //结束
            return result;
        }
    }
};
template <class T>
EdgeGraph<T>::EdgeGraph(int vNum, int eNum)
{
    vexNum = vNum;
    arcNum = eNum;
    //dist数组的初始化,让对角线上为0,其余为无穷大
    for (int i = 0; i < vexNum; i++)
    {
        for (int j = 0; j < vexNum; j++)
        {
            if (i == j)
            {
                dist[i][j] = 0;
                newdist[i][j] = 0;
            }
            else
            {
                dist[i][j] = INT_MAX;
                newdist[i][j] = INT_MAX;
            }
        }
    }
    T f, t;
    int w;
    //顶点的初始化
    for (int i = 0; i < vexNum; i++)
    {
        vertex[i] = i + '0';  //这里得转化一下,当成字符
    }
    //short数组的初始化
    for (int i = 0; i < vexNum; i++)
    {

        shortP[i] = 0;
    }
    //cout << "请输入边依附的两个顶点和权值:\n";
    for (int i = 0; i < arcNum; i++)
    {
        cin >> f;
        cin >> t;
        cin >> w;
        dist[getIndex(f)][getIndex(t)] = w;
    }

}
template <class T>
void EdgeGraph<T>::Floyd()
{
    //初始化path
    for (int i = 0; i < vexNum; i++)
    {
        for (int j = 0; j < vexNum; j++)
        {
            if (dist[i][j] != INT_MAX && dist[i][j] != 0) //如果两个地点有路线连接,并且起点和终点不是同一个位置
            {
                path[i][j] = { vertex[i],vertex[j] }; //把起始位置和终点位置拼成一个字符串,存入path 中
            }
            else
                path[i][j] = "";  //否则path中存空
        }
    }

    //开始查找
    string result; //记录路径结果
    for (int k = 0; k < vexNum; k++)
    {
        for (int i = 0; i < vexNum; i++)
        {
            for (int j = 0; j < vexNum; j++)
            {
                if (dist[i][k] + dist[k][j] < dist[i][j] && dist[i][k] != INT_MAX && dist[k][j] != INT_MAX) //当找到更短的路径
                {
                    dist[i][j] = dist[i][k] + dist[k][j]; //更新短路径
                    result = Combine(path[i][k], path[k][j]);  //并记录path,存入到path数组中
                    path[i][j] = result;
                }
            }
        }
    }
    //输出
    //cout << "显示每对顶点间的最短路径:" << endl;
    for (int i = 0; i < vexNum; ++i) {
        for (int j = 0; j < vexNum; ++j) {
            if (i == j)
                continue;
            else {
                if (dist[i][j] == INT_MAX) {
                    newdist[i][j] = INT_MAX;
                }
                else {
                    newdist[i][j] = dist[i][j];
                }
            }
        }
    }
}
//调用Floyd算法,求每对顶点间最短路径长度的矩阵;
template <class T>
void EdgeGraph<T>::getShortPath()
{
    Floyd();

    for (int i = 0; i < vexNum; i++)
    {
        for (int j = 0; j < vexNum; j++)
        {
            if (newdist[i][j] != INT_MAX)
                shortP[i] += newdist[i][j];
            else
            {
                shortP[i] = INT_MAX;
                break;
            }
        }
    }
    int min = INT_MAX, index = 0;
    for (int i = 0; i < vexNum; i++)
    {
        if (shortP[i] < min)
        {
            min = shortP[i];
            index = i;
        }
    }
    cout << "选址地点为" << index << endl;
    cout << "最短路径长度为" << shortP[index];
}
int main()
{
    int vNum, eNum;
    //cout << "请输入顶点个数和边的个数:";
    cin >> vNum >> eNum;
    EdgeGraph<char> graph(vNum, eNum);
    graph.getShortPath();
    return 0;
}


/*Prim算法求最小生成树*/
#include <iostream>
#include <limits.h>
#include <string> // 包含string以便处理顶点的字符表示
#define MAX_V_NUM 20

using namespace std;

struct closedge
{
    char adjvex; // 邻接点的字符表示
    int lowcost; // 到邻接点的最小权值
};

closedge shortEdge[MAX_V_NUM]; // 存储候选最短边集

class MGraph
{
private:
    char vertex[MAX_V_NUM]; // 图的顶点数组
    int arc[MAX_V_NUM][MAX_V_NUM]; // 图的邻接矩阵
    int vexNum, arcNum; // 顶点数和边数

public:
    MGraph(); // 构造函数
    void Prim(int start); // 实现Prim算法
};

MGraph::MGraph()
{
    cout << "请输入顶点的个数:";
    cin >> vexNum;
    cout << "请依次输入" << vexNum << "个顶点的值:" << endl;
    for (int i = 0; i < vexNum; i++)
    {
        cin >> vertex[i];
    }
    cout << "请输入边的个数:";
    cin >> arcNum;
    char vi, vj;
    int w;
    // 初始化邻接矩阵
    for (int i = 0; i < vexNum; i++)
    {
        for (int j = 0; j < vexNum; j++)
        {
            if (i == j)
            {
                arc[i][j] = 0;
            }
            else
            {
                arc[i][j] = INT_MAX;
            }
        }
    }
    cout << "请依次输入" << arcNum << "个边的起点、终点和权值:" << endl;
    for (int i = 0; i < arcNum; i++)
    {
        cin >> vi >> vj >> w;
        arc[vi - 'A'][vj - 'A'] = w;
        arc[vj - 'A'][vi - 'A'] = w; // 因为是无向图
    }
    // 假设从顶点0开始Prim算法
    Prim(0);
}

void MGraph::Prim(int start)
{
    // 初始化shortEdge数组
    for (int i = 0; i < vexNum; i++)
    {
        shortEdge[i].lowcost = arc[start][i];
        shortEdge[i].adjvex = start;
    }
    shortEdge[start].lowcost = 0;
    cout << "最小生成树是:" << endl;
    for (int i = 0; i < vexNum - 1; i++)
    {
        int k = 0;
        for (int j = 0; j < vexNum; j++)
        {
            if (shortEdge[j].lowcost != 0 && shortEdge[j].lowcost != INT_MAX) {
                k = j;
                break;
            }
        }
        for (int j = 0; j < vexNum; j++) {
            if (shortEdge[j].lowcost != 0 && shortEdge[k].lowcost > shortEdge[j].lowcost)
            {
                k = j;
                break;
            }
        }
        // 输出最小边
        cout << "(" << vertex[shortEdge[k].adjvex] << vertex[k] << ")" << shortEdge[k].lowcost << endl;
        // 将找到的最小边标记为0,表示已访问
        shortEdge[k].lowcost = 0;
        for (int j = 0; j < vexNum; j++)
        {
            if (arc[k][j] != 0 && arc[k][j] < shortEdge[j].lowcost)
            {
                shortEdge[j].lowcost = arc[k][j];
                shortEdge[j].adjvex = k;
            }
        }
    }
}

int main()
{
    MGraph graph;
    return 0;
}

/*Kruskal算法求最小生成树*/
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 10000;
template <class T>
struct EdgeType
{
    T from, to;     //边依附的两个顶点
    int weight;      //边上的权值
};
template <class T>
class EdgeGraph
{
private:
    char* vertex;  //存放图顶点的数组
    EdgeType<char>* edge;      //存放边的数组
    int vertexNum, edgeNum;         //图的顶点数和边数
public:
    EdgeGraph(int vNum, int eNum);//构造函数
    void inputGraph();//输入图
    void Kruskal();
    int getIndex(char v)
    {
        for (int i = 0; i < vertexNum; i++) {
            if (vertex[i] == v) {
                return i;
            }
        }
        return -1; // 如果找不到顶点,返回-1
    }
    void sorts();
private:
    T findRoot(int parent[], T v);//找到树的根
};
template <class T>
EdgeGraph<T>::EdgeGraph(int vNum, int eNum)
{
    vertexNum = vNum;
    edgeNum = eNum;
    vertex = new char[vertexNum];
    edge = new EdgeType<T>[edgeNum];
    char v;
    T f, t;
    int w;
    cout << "请输入顶点的值:";
    for (int i = 0; i < vertexNum; i++)
    {
        cin >> v;
        vertex[i] = v;
    }
    cout << "请输入边的起点终点和权值:\n";
    for (int i = 0; i < edgeNum; i++)
    {
        cin >> f >> t >> w;
        edge[i].from = f;
        edge[i].to = t;
        edge[i].weight = w;
    }
    sorts();

}
//对weight排序
// 最开始写的冒泡排序,但是有问题
// 冒泡排序不是对边的数组edge中的元素进行排序,而是对数组的索引进行排序。这意味着数组edge中的元素并没有按照权值从小到大进行排序,而是数组的索引被重新排列,使得具有较小权值的边的索引在前。这并不是Kruskal算法所需要的。
// 需要对边的数组edge中的EdgeType对象按照权值进行排序,而不是对索引进行排序。
// 修正后,使用了C++11的lambda表达式来定义排序准则,即按照weight成员进行比较。这样,edge数组中的EdgeType对象将根据它们的权值进行排序,而不是它们的索引。
template <class T>
void EdgeGraph<T>::sorts()
{
    // 使用标准库的sort函数对边按照权值进行排序

    sort(edge, edge + edgeNum, [](const EdgeType<T>& a, const EdgeType<T>& b) {
        return a.weight < b.weight;
        });

}
template <class T>
void EdgeGraph<T>::Kruskal()
{
    int parent[MAX] = { 0 };
    T vex1, vex2;
    sorts();
    for (int i = 0; i < vertexNum; i++)
    {
        parent[i] = -1;
    }

    for (int num = 0, i = 0; i < edgeNum; i++)
    {
        //找到所在生成树的根节点
        int idx1 = getIndex(edge[i].from);
        int idx2 = getIndex(edge[i].to);
        vex1 = findRoot(parent, idx1);
        vex2 = findRoot(parent, idx2);
        if (vex1 != vex2) //如果两个根节点不同,不会构成环
        {
            cout << "(" << edge[i].from << "," << edge[i].to << ")" << edge[i].weight << endl;
            parent[vex2] = vex1;//合并生成树
            num++;
            if (num == vertexNum - 1)  //循环了顶点数-1次,提前返回
                return;
        }
    }
}
//求根节点
template <class T>
T EdgeGraph<T>::findRoot(int parent[], T v)
{
    T t = v;
    while (parent[t] > -1)
    {
        t = parent[t];
    }
    return t;
}
int main()
{
    int vNum, eNum;
    cout << "请输入图的顶点数和边数:";
    cin >> vNum >> eNum;
    EdgeGraph<char> edgegraph(vNum, eNum);
    cout << "用Kruskal算法生成最小生成树的生成次序为:\n";
    edgegraph.Kruskal();
    return 0;
}


/*Dijkstra算法求最短路径*/
#include<iostream>
#include<algorithm>
#include<string>
#include<limits.h>
using namespace std;
const int MAX_V_NUM = 100;
template <class T>
struct EdgeType
{
    T from, to;     //边依附的两个顶点
    int weight;      //边上的权值
};

template <class T>
class EdgeGraph
{
private:
    char vertex[MAX_V_NUM] = { 0 };  //存放图顶点的数组
    int arc[MAX_V_NUM][MAX_V_NUM] = { INT_MAX };
    int vexNum, arcNum;         //图的顶点数和边数
    int s[MAX_V_NUM] = { 0 };  //存储顶点是否被查找过
    int start;  //输入的起始顶点下标
public:
    EdgeGraph(int vNum, int eNum);
    void Dijkstra();
    int findMinDist(int* dist);  //在dist中查找s[i]为0的最小值元素
    int getIndex(char v)
    {
        for (int i = 0; i < vexNum; i++) {
            if (vertex[i] == v) {
                return i;
            }
        }
        return -1; // 如果找不到顶点,返回-1
    }
    void displayPath(int* dist, int* path);
};
template <class T>
EdgeGraph<T>::EdgeGraph(int vNum, int eNum)
{
    int u, v, w;
    vexNum = vNum;
    arcNum = eNum;

    //arc初始化
    for (int i = 0; i < vexNum; i++)
    {
        for (int j = 0; j < vexNum; j++)
        {
            if (i != j)
                arc[i][j] = INT_MAX;
            else
                arc[i][j] = 0;
        }
    }
    cout << "请输入顶点的值";
    for (int i = 0; i < vexNum; i++)
    {
        cin >> vertex[i];
    }
    cout << "依次输入边的起点编号,终点编号和权值\n";
    for (int i = 0; i < arcNum; i++)
    {
        cin >> u >> v >> w;
        arc[u][v] = w;
    }
    cout << "请输入起始顶点:";
    char c;
    cin >> c;
    start = getIndex(c);
}

//迪杰斯特拉
template <class T>
void EdgeGraph<T>::Dijkstra()
{
    int dist[MAX_V_NUM] = { INT_MAX };
    int path[MAX_V_NUM] = { -1 };
    int num = 0; //记录顶点数
    int min;//记录最小值

    for (int i = 0; i < vexNum; i++)
    {
        dist[i] = arc[start][i];
        if (dist[i] != INT_MAX)
            path[i] = start;
        else
            path[i] = -1;
    }

    //s数组的初始化
    for (int i = 0; i < vexNum; i++)
    {
        s[i] = 0;
    }
    s[start] = 1;//顶点放入集合s。
    num = 1;
    while (num < vexNum) //当顶点数小于图的顶点数
    {
        min = findMinDist(dist); //找到最小值
        for (int i = 0; i < vexNum; i++)
        {    //更新dist和path
            if ((s[i] == 0) && (dist[min] + arc[min][i] < dist[i]) && dist[min] != INT_MAX && arc[min][i] != INT_MAX)  //找到更短的距离,防止距离为无穷的情况
            {
                dist[i] = dist[min] + arc[min][i];
                path[i] = min;
            }
        }
        s[min] = 1; //将新生成的点加入s
        num++;
    }
    //打印输出起始点到各顶点的最短路径
    displayPath(dist, path);
}

//找最小值
template <class T>
int EdgeGraph<T>::findMinDist(int* dist)
{
    int min = INT_MAX;
    int index = -1;
    for (int i = 0; i < vexNum; i++) //在dist数组中没有生成树(s[i]=0)的结点中查找
    {
        if (s[i] == 0)
        {
            if (dist[i] < min)
            {
                min = dist[i];
                index = i;
            }
        }
    }
    return index;
}

//输出路径
template <class T>
void EdgeGraph<T>::displayPath(int* dist, int* path)
{
    char result[MAX_V_NUM] = { 0 };
    int k = 0;
    cout << "输出从" << vertex[start] << "到各个顶点的最短路径:\n";
    for (int i = 0; i < vexNum; i++)
    {
        if (i != start)
        {
            if (dist[i] <= 0 || dist[i] == INT_MAX)
            {
                cout << endl;
                cout << "从" << vertex[start] << "到" << vertex[i] << "没有路径." << endl;
            }
            else
            {
                cout << endl;
                cout << "从" << vertex[start] << "到" << vertex[i] << "顶点的最短路径长度为:" << dist[i] << endl;
                cout << "从" << vertex[start] << "到" << vertex[i] << "顶点的最短路径为:" << vertex[start];
                int j = i;
                while (j != start)
                {
                    result[k++] = vertex[j];
                    j = path[j];
                }
                for (int l = k - 1; l >= 0; l--)
                {
                    cout << "->" << result[l];
                }
                k = 0;  //将k归0,进行下一次路径记录
                cout << endl;
            }
        }
    }
    cout << endl;
}

int main()
{
    int vNum, eNum;
    cout << "请输入顶点个数和边的个数:";
    cin >> vNum >> eNum;
    EdgeGraph<char> graph(vNum, eNum);
    graph.Dijkstra();
    return 0;
}

/*二叉树的镜像*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int MAX = 1000;
struct BiNode
{
    char data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};

class BiTree {
private:
    BiNode* root;
public:
    BiTree() { root = creat(root); }
    ~BiTree() {
        release(root);
    }
    BiNode* getRoot() { return root; }
    BiNode* creat(BiNode* bt); //构造函数调用
    void release(BiNode* bt);  //析构函数调用,释放树的存储空间
    void Mirror(BiNode* pRoot);//镜像
    void preOrder(BiNode* bt);//前序输出

};
BiNode* BiTree::creat(BiNode* bt)
{
    char ch;
    cin >> ch;

    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new BiNode;
        bt->data = ch;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);

    }
    return bt;
}

void BiTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        delete bt;
    }
}
//镜像
void BiTree::Mirror(BiNode* bt)
{
    if (bt == nullptr)
        return;
    swap(bt->lchild, bt->rchild);//交换左右子树
    Mirror(bt->lchild);
    Mirror(bt->rchild);
}
void BiTree::preOrder(BiNode* bt)
{
    if (bt == NULL)
    {
        return;
    }
    cout << bt->data;
    preOrder(bt->lchild);
    preOrder(bt->rchild);
}
int main()
{
    BiTree tree;
    tree.Mirror(tree.getRoot());
    cout << "镜像后二叉树的前序遍历序列是:";
    tree.preOrder(tree.getRoot());
    return 0;
}

/*求二叉树第k层结点的个数*/
#include<iostream>
#include<stdio.h>
#include<string.h>
const int MAX = 1000;
using namespace std;
struct BiNode
{
    char data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};

class BiTree {
private:
    BiNode* root;
public:
    BiTree()
    {
        root = creat(root);
    }
    BiNode* creat(BiNode* bt);
    void mirror(BiNode* bt);
    void preOrder(BiNode* bt);
    BiNode* getRoot() { return root; }
    int getknode(BiNode* bt, int k);
};
BiNode* BiTree::creat(BiNode* bt)
{
    char ch;
    cin >> ch;
    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new BiNode;
        bt->data = ch;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);
    }
    return bt;
}

/**前序遍历*/
void BiTree::preOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else {
        cout << bt->data;
        preOrder(bt->lchild);
        preOrder(bt->rchild);
    }
}
// 求结点个数
int BiTree::getknode(BiNode* bt, int k)
{
    if (bt == NULL || k <= 0) //二叉树为空时
        return 0;
    if (bt != NULL && k == 1) //二叉树只有一个节点(1层)时
        return 1;
    return getknode(bt->lchild, k - 1) + getknode(bt->rchild, k - 1);
    // 先计算左子树第k-1层的结点个数,再计算右子树第k-1层结点个数,相加
}
int main()
{
    BiTree tree;
    int a, b;
    cin >> a;
    b = tree.getknode(tree.getRoot(), a);
    cout << b;
    return 0;
}

/*二叉排序树*/
#include <iostream>
#include <algorithm>
#include <limits.h>
#include<string>
using namespace std;
const int MAX = 100;
struct BiNode
{
    int data;
    BiNode* lchild, * rchild;//左右儿子指针
};
BiNode* root = NULL;
static bool flag = false;
void inOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        inOrder(bt->lchild);
        cout << bt->data << " ";
        inOrder(bt->rchild);
    }
}
void preOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        cout << bt->data << " ";
        preOrder(bt->lchild);
        preOrder(bt->rchild);
    }
}
void release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        delete bt;
        bt = NULL;
    }
}
void postOrder(BiNode* bt)
{
    if (bt != NULL)
    {
        postOrder(bt->lchild);
        postOrder(bt->rchild);
        cout << "Delete:" << bt->data << endl;
    }
}
void Insert(BiNode*& bt, int num)
{
    if (bt == NULL)
    {
        bt = new BiNode;
        bt->data = num;
        bt->lchild = NULL;
        bt->rchild = NULL;
    }
    else
    {
        if (num < bt->data)
            Insert(bt->lchild, num);
        else if (num > bt->data)
            Insert(bt->rchild, num);
    }
}
bool Search(BiNode* bt, int key)
{

    if (bt == NULL)
        return false;
    else
    {
        if (key < bt->data)
        {
            cout << bt->data << " ";
            Search(bt->lchild, key);
        }
        else if (key > bt->data)
        {
            cout << bt->data << " ";
            Search(bt->rchild, key);
        }
        else
        {
            cout << bt->data << " ";
            flag = true;
        }
        return flag;
    }
}
//删除结点
void deleteNode(BiNode*& bt)
{
    BiNode* p;
    if (bt->lchild == NULL && bt->rchild == NULL) //叶子结点
    {                                             //直接删除,再把该位置设为空
        p = bt;
        bt = NULL;
        delete p;
    }
    else if (bt->rchild == NULL) //右子树为空,只有左子树
    {
        p = bt;
        bt = bt->lchild;  //把删除结点的左子树拼接到删除节点的父节点的右边,作为父节点的右子树
        delete p;
    }
    else if (bt->lchild == NULL) //左子树为空,只有右子树,同上
    {
        p = bt;
        bt = bt->rchild;
        delete p;
    }
    else  //左右子树都不为空|将要删除结点的左子树中最大的结点替换该删除的结点
    {
        BiNode* parent, * pre;
        parent = bt;
        pre = bt->lchild;
        //转左,然后向右到尽头
        while (pre->rchild)
        {
            parent = pre;
            pre = pre->rchild;

        }
        bt->data = pre->data; //将根节点的左子树中的最大的节点赋给根节点,原本的根节点被替代
        if (parent != bt)
            parent->rchild = pre->lchild;  //pre的lchild与parent建立联系,pre被删掉
        else
            parent->lchild = pre->lchild;  //原来pre指向的结点,也就是最大的结点被删掉
        delete pre;
    }
}

//根据指定的关键数据找到要删除的节点的位置
bool deleteBST(BiNode*& bt, int key)
{
    if (bt == NULL)
    {
        return false;
    }
    else
    {
        if (bt->data == key) //找到关键词
            deleteNode(bt);  //删除
        else if (key < bt->data)  //如果关键词比当前结点数据小,继续在其左子树中查找
            return deleteBST(bt->lchild, key);
        else  //如果关键词比当前结点数据大,在其右子树中查找
            return deleteBST(bt->rchild, key);
        return true;  //查找成功
    }
}

int main()
{
    int n, key;
    int array[MAX] = { 0 };
    cout << "请输入二叉树结点个数:\n";
    cin >> n;
    cout << "请输入结点数据:\n";
    for (int i = 0; i < n; i++)
    {
        cin >> array[i];
    }
    for (int i = 0; i < n; i++)
    {
        Insert(root, array[i]);
    }
    //开始查找
    cout << "请输入待查找的整数:\n";
    cin >> key;
    cout << "Searching..." << endl;
    if (Search(root, key))
        cout << "\nFound." << endl;
    else
        cout << "\nNot found." << endl;

    cout << "请输入待删除的结点:\n";
    cin >> key;
    //开始删除
    if (deleteBST(root, key))
    {
        cout << "Found." << endl;
        cout << "PreOrder sequence after deleted: ";
        preOrder(root);
        cout << "\nInOrder sequence after deleted: ";
        inOrder(root);
    }
    else
        cout << "Not found." << endl;
    //销毁二叉树
    cout << endl << "Destroy tree..." << endl;
    postOrder(root);
    release(root);
    return 0;
}

/*将二叉排序树转换成双向链表*/
#include<iostream>
using namespace std;
const int MAX = 1000;
struct BiNode {
    int data;
    BiNode* lchild, * rchild;
};

class BiSortTree {
private:
    BiNode* root;  //指向根结点的头指针
    BiNode* rear;  //指向尾结点的指针
    //BiNode  *pre;   //---指向当前访问的结点的前序节点
public:
    BiSortTree(int array[], int arrayLength);  //构造函数,建立一棵二叉树
    ~BiSortTree();          //---
    void convertBiToLink(); //---二叉排序树转换成双向链表
    void DisplayLink();     //---显示双向链表
    void ReverseDisplayLink(); //---逆序显示
    void release(BiNode* bt);
private:
    void insertBST(BiNode*& bt, BiNode* key);
    void convert(BiNode* bt); //---二叉排序树转换成双向链表的递归程序
};
BiSortTree::BiSortTree(int array[], int arrayLength)
{
    root = NULL;
    for (int i = 0; i < arrayLength; i++)
    {
        BiNode* p = new BiNode;
        p->lchild = p->rchild = NULL;
        p->data = array[i];
        insertBST(root, p);
    }
}
BiSortTree::~BiSortTree()
{
    release(root);
}
void BiSortTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        delete bt;
        bt = NULL;
    }
}
// 插入节点
void BiSortTree::insertBST(BiNode*& bt, BiNode* key)
{
    if (bt == NULL)
    {
        bt = new BiNode;
        bt->data = key->data;
        bt->lchild = NULL;
        bt->rchild = NULL;
    }
    else
    {
        if (key->data < bt->data)
            insertBST(bt->lchild, key);
        else if (key->data > bt->data)
            insertBST(bt->rchild, key);
    }
}

/*二叉排序树转换成双向链表
二叉排序树的递归定义是:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树;
实现思路:
1.二叉排序树的特点就是一个结点的左子树比它小,右子树比它大,所以可以根据中序遍历得到一棵排序的序列。
2.由于不能创建新结点,那么我们只能去修改原始二叉树的指针。
  这里我们让指向左子树的指针变为链表中指向前序结点的指针,而指向右子树的指针变为链表中指向后一个结点的指针。
*/
void BiSortTree::convertBiToLink()
{
    if (root == NULL)
        return;
    else
    {
        convert(root);
        //将root指向链表的头部
        while (root->lchild) //root从当前位置出发,向其左孩子移动,直到左孩子为空,到达头部
        {
            root = root->lchild;
        }
    }
}
//二叉树转换成双向链表,采用中序遍历,当访问根节点的时候实现转换
void BiSortTree::convert(BiNode* bt)
{
    static BiNode* pre = NULL;  //指向当前访问节点的前序结点
    if (bt == NULL)
    {
        return;
    }
    else
    {
        convert(bt->lchild);  //访问左子树
        //访问根节点
        if (pre == NULL) // 如果是链表的第一个节点
        {
            root = bt; // 设置链表的头部
        }
        else
        {
            pre->rchild = bt; // 将前一个节点的右指针指向当前节点
            bt->lchild = pre; // 将当前节点的左指针指向前一个节点
        }
        pre = bt;           // 当前根节点变成前序结点
        convert(bt->rchild);  // 访问右子树
    }
}
//正序输出二叉排序树链表
void BiSortTree::DisplayLink()
{
    BiNode* p;
    p = root;
    while (p)
    {
        cout << p->data << " ";
        p = p->rchild;
    }
    cout << endl;
}
//逆序输出二叉排序树链表
void BiSortTree::ReverseDisplayLink()
{
    if (root == NULL)
        return; // 如果链表为空,直接返回
    BiNode* p = root;
    // 找到链表的最后一个节点
    while (p->rchild)
    {
        p = p->rchild;
    }
    // 逆序输出
    while (p)
    {
        cout << p->data << " ";
        BiNode* temp = p->lchild;
        delete p; // 释放节点以避免内存泄漏
        p = temp;
    }
    root = NULL; // 清空链表头部指针
    rear = NULL; // 清空链表尾部指针
}
int main()
{
    int n;
    cin >> n;
    int array[MAX] = { 0 };
    for (int i = 0; i < n; i++)
    {
        cin >> array[i];
    }
    cout << "Convert binary sort tree into linked list..." << endl;
    BiSortTree BSTLink(array, n);
    BSTLink.convertBiToLink();
    BSTLink.DisplayLink();

    cout << "Reverse display link...\n";
    BSTLink.ReverseDisplayLink();
    return 0;
}

/*判断是否是平衡二叉树*/
#include <iostream>
using namespace std;
struct BiNode
{
    int data;
    BiNode* lchild, * rchild;
};
BiNode* root = NULL;
//求二叉树的深度
int treeHeight(BiNode* bt)
{
    if (bt == NULL)
        return 0;
    else
    {
        int h1 = treeHeight(bt->lchild);
        int h2 = treeHeight(bt->rchild);
        return h1 > h2 ? h1 + 1 : h2 + 1; // 取左右子树中的较高者,并加上根节点
    }
}
// 判断是否为平衡二叉树
bool isBalance(BiNode* bt, int& height) {
    if (bt == NULL) {
        height = 0;
        return true;
    }
    int leftHeight, rightHeight;
    if (isBalance(bt->lchild, leftHeight) && isBalance(bt->rchild, rightHeight)) {
        if (abs(leftHeight - rightHeight) <= 1) {
            height = max(leftHeight, rightHeight) + 1;  //取左右子树的较大者,并加上根节点
            return true;
        }
    }
    return false;

}
// 插入数据
void insertBST(BiNode*& bt, int key)
{
    if (bt == NULL)
    {
        bt = new BiNode;
        bt->data = key;
        bt->lchild = NULL;
        bt->rchild = NULL;
    }
    else
    {
        if (key < bt->data)
            insertBST(bt->lchild, key);
        else if (key > bt->data)
            insertBST(bt->rchild, key);
    }
}

//中序输出二叉树
void Display(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        Display(bt->lchild);
        cout << bt->data << " ";
        Display(bt->rchild);

    }
}
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        int num;
        cin >> num;
        insertBST(root, num);
    }
    /* cout << "inorder\n";
     Display(root);*/
    bool flag = false;
    int height;
    flag = isBalance(root, height);
    if (flag)
    {
        cout << "是二叉平衡树";
    }
    else
    {
        cout << "不是二叉平衡树";
    }
    return 0;
}

/*除留取余法构造散列表*/
#include <iostream>
#include <math.h>
using namespace std;
#define NULLKEY -32760
bool isPrim(int num)
{
    if (num <= 1)
        return false;
    if (num <= 3)
        return true;
    if (num % 2 == 0 || num % 3 == 0)
        return false;
    for (int i = 5; i * i <= num; i += 6) {
        if (num % i == 0 || num % (i + 2) == 0)
            return false;
    }
    return true;
}

class HashTable
{
private:
    int* elem; //数据元素存储地址,动态分配数组
    int size; //哈希表长度
    int n;    //当前元素个数
    int p;    //哈希函数的除数
public:
    HashTable(int n, int size)
    {
        this->n = n;
        this->elem = new int[size];
        this->size = size;
        for (int i = 0; i < size; i++)
        {
            this->elem[i] = NULLKEY;
        }
        p = 2;
        //倒序搜索,求小于size的最大质数
        for (int i = size; i > 0; i--)
        {
            if (isPrim(i))
            {
                p = i;
                break;
            }
        }
        cout << "p=" << p << endl;
    }
    int hash(int data)
    {
        return data % p;
    }
    //哈希函数除留取余法,可用于构造哈希表,用开放性定址法线性探测解决冲突
    void insert(int data)
    {
        int hashAddress = hash(data);
        //发生冲突
        while (this->elem[hashAddress] != NULLKEY)
        {
            //利用开放定址法解决冲突
            hashAddress = (++hashAddress) % size;
        }
        this->elem[hashAddress] = data;
    }
    //哈希表的查找算法
    int search(int data)
    {
        int hashAddress = hash(data);  //求哈希地址
        while (this->elem[hashAddress] != data) //发生冲突
        {
            //利用开放定址法解决冲突
            hashAddress = (++hashAddress) % size;
            //如果查到的地址中数据位空,或者经过一圈的遍历回到查找地址时,说明查找失败
            if (this->elem[hashAddress] == NULLKEY || hashAddress == hash(data))
            {
                return -1;
            }
        }
        return hashAddress;
    }
    void displayHashTable()
    {
        for (int i = 0; i < size; i++)
        {
            if (this->elem[i] != NULLKEY)
                cout << this->elem[i] << " ";
            else
                cout << "^ ";
        }
        cout << endl;
    }
};

int main()
{
    int i, result;
    int n, m;
    cin >> n >> m;
    int arr[100];
    for (int i = 0; i < n; i++)
    {
        cin >> arr[i];
    }
    HashTable hashTable(n, m);
    //利用插入函数构建哈希表
    for (i = 0; i < n; i++)
    {
        hashTable.insert(arr[i]);
    }
    cout << "打印哈希表";
    hashTable.displayHashTable();
    cout << "输入要查找的数字";
    int num;
    cin >> num;
    //调用查找法
    result = hashTable.search(num);
    if (result != -1)
        cout << num << "在哈希表中的位置是" << result;
    else
        cout << "查找失败";
    return 0;
}


/*拓扑排序(AOV网)*/
#include<iostream>
#include<stack>
#include<cstring>
#define MAX 100
using namespace std;
typedef struct ArcNode          //边结点
{
    int adjvex;                 //顶点下标
    ArcNode* next;
} ArcNode;
typedef struct
{
    int in;                     //in是入度
    int vertex;              //顶点信息
    ArcNode* firstEdge;
} vertexNode, VertexNode[MAX];

class ALGraph
{
private:
    int vertexNum, arcNum;   //顶点数,边数
    VertexNode adjList;     //顶点数组
    stack<vertexNode> s;    //栈
    int count = 0;            //计数
public:
    ALGraph(int v[], int n, int e);
    void TopologicalSort(); //拓扑排序
};
void ALGraph::TopologicalSort()
{
    for (int i = 0; i < vertexNum; i++)  //in为0则压栈
    {
        if (adjList[i].in == 0)
        {
            s.push(adjList[i]);
        }
    }
    while (!s.empty())               //循环终止条件:栈为空
    {
        vertexNode v = s.top();       //弹栈输出
        s.pop();
        cout << v.vertex << " ";
        count++;                    //计数加一
        ArcNode* a = v.firstEdge;
        while (a)                    //对弹出的结点遍历,所有遍历过的结点的in-1
        {
            adjList[a->adjvex].in--;
            int tmp = adjList[a->adjvex].in;
            if (tmp == 0)              //如果某结点的in变为0,则将其压栈
            {
                s.push(adjList[a->adjvex]);
            }
            a = a->next;
        }
    }
    if (count < vertexNum)
        cout << "图中存在环,无法拓扑排序";//如果计数小于顶点数则说明有环
}
ALGraph::ALGraph(int v[], int n, int e)    //构造函数
{
    vertexNum = n;
    arcNum = e;
    for (int i = 0; i < vertexNum; i++)          //顶点初始化
    {
        adjList[i].in = 0;
        adjList[i].vertex = v[i];
        adjList[i].firstEdge = NULL;
    }
    ArcNode* s;
    int vi, vj;
    for (int i = 0; i < arcNum; i++)
    {
        s = new ArcNode;
        cin >> vi >> vj;
        s->adjvex = vj;
        s->next = adjList[vi].firstEdge;      //头插法
        adjList[vi].firstEdge = s;
        adjList[vj].in++;                   //入度加一
    }
}
int main()
{
    int n, e;
    cin >> n >> e;
    int v[MAX];
    for (int i = 0; i < n; i++)
    {
        v[i] = i;
    }
    ALGraph algraph(v, n, e);
    algraph.TopologicalSort();
    return 0;
}

/*关键路径(AOE网)*/
#include <iostream>
#include <stdio.h>
using namespace std;
const int MAX = 30;
struct ArcNode
{
    int weight;
    int adjvex;
    ArcNode* next;
};
struct VertexNode
{
    int in; //入度
    char vertex;  //图的顶点
    ArcNode* firstEdge;  //指向第一个边表
};
class ALGraph
{
private:
    VertexNode* adjList; //邻接表
    int vertexNum, arcNum;
    int* ve, * vl; //分别为事件最早发生时间的数组,事件最迟发生时间的数组
public:
    ALGraph(char v[], int n, int e);
    ~ALGraph();
    void inputEdges();
    bool setEdge(int vi, int vj, int weight); //设置边
    void display();
    bool Topological(int result[], int& count); //拓扑排序
    bool GriticalPath();  //求关键路径
};
ALGraph::ALGraph(char v[], int n, int e)
{
    vertexNum = n;
    arcNum = e;
    adjList = new VertexNode[vertexNum]; //创建
    for (int i = 0; i < vertexNum; i++)
    {
        adjList[i].in = 0;
        adjList[i].vertex = v[i];
        adjList[i].firstEdge = NULL;
    }
    ve = new int[vertexNum];
    vl = new int[vertexNum];
}

void ALGraph::inputEdges()
{
    //cout << "输入" << endl;
    for (int i = 0; i < arcNum; i++)
    {
        int vi, vj, weight;
        cin >> vi >> vj >> weight;
        if (!setEdge(vi, vj, weight))
        {
            cout << "超过范围,重新输入" << endl;
            i--;
        }
    }
}
bool ALGraph::setEdge(int vi, int vj, int weight)
{
    ArcNode* s;
    if (vi >= 0 && vi < vertexNum && vj >= 0 && vj < vertexNum && vi != vj)
    {
        //创建一个边结点vj
        s = new ArcNode;
        s->adjvex = vj;
        s->weight = weight;
        // 把边结点vj插入顶点表的vi项的邻接表中,成为第一个节点
        s->next = adjList[vi].firstEdge;
        adjList[vi].firstEdge = s;
        // 入度+1
        adjList[vj].in++;
        return true;
    }
    else
    {
        return false;
    }
}
ALGraph::~ALGraph()
{
    ArcNode* p, * pre;
    // 顶点表指向所有边的结点删除
    for (int i = 0; i < vertexNum; i++)
    {
        p = adjList[i].firstEdge;
        adjList[i].firstEdge = NULL;
        while (p)
        {
            pre = p;
            p = p->next;
            delete pre;
        }
    }
    delete[] adjList;
    delete[] ve;
    delete[] vl;
}
bool ALGraph::Topological(int result[], int& count)
{
    int stack[MAX];
    int top = -1;
    int inVex;
    int outVex;
    ArcNode* p;
    for (int i = 0; i < vertexNum; i++)
    {
        ve[i] = 0;
    }
    for (int i = 0; i < vertexNum; i++)
    {
        if (adjList[i].in == 0)
        {
            stack[++top] = i;
        }
    }
    count = 0;  //统计有多少个顶点被处理过了
    while (top != -1)
    {
        inVex = stack[top--]; //出栈
        result[count] = inVex; //存入数组
        count++; //下一次存储
        //找出当前处理的顶点的所有边
        p = adjList[inVex].firstEdge;
        while (p)  //扫描边表 “删掉”边
        {
            outVex = p->adjvex; //获取当前边表的终点值
            adjList[outVex].in--; //入度减1
            if (adjList[outVex].in == 0) //把入度为0的压入堆栈
                stack[++top] = outVex;
            if (ve[inVex] + p->weight > ve[outVex]) //找到最大的时间
                ve[outVex] = ve[inVex] + p->weight;
            p = p->next;
        }
    }
    // 判断排序是否正确
    if (count == vertexNum) //该拓扑排序是无环图
    {
        return true;
    }
    else
        return false;

}
bool ALGraph::GriticalPath()
{
    int resultStack[MAX]; //存储拓扑排序的序列的栈
    int resultTop;  //栈顶指针
    ArcNode* p;
    int i, count;
    int inVex, outVex;
    if (!Topological(resultStack, count))
    {
        return false;
    }

    resultTop = count - 1; //指向栈顶
    inVex = resultStack[resultTop--]; //栈顶元素出栈
    //求Vl数组,倒序求最小值
    //初始化
    for (i = 0; i < vertexNum; i++)
    {
        vl[i] = ve[inVex];
    }
    while (resultTop != -1)
    {
        inVex = resultStack[resultTop--];
        p = adjList[inVex].firstEdge;
        while (p)
        {
            outVex = p->adjvex;
            if (vl[inVex] > vl[outVex] - p->weight)
            {
                vl[inVex] = vl[outVex] - p->weight;
            }
            p = p->next;
        }
    }

    for (inVex = 0; inVex < vertexNum; inVex++)//从上往下扫描边表
    {
        p = adjList[inVex].firstEdge;
        while (p)
        {
            outVex = p->adjvex;
            int weight = p->weight;
            int ee = ve[inVex]; //活动的最早开始时间
            int el = vl[outVex] - weight;  //活动的最晚开始时间
            if (ee == el)
            {
                cout << "<" << inVex << "," << outVex << ">" << weight << " ";
            }
            p = p->next;
        }
    }
    return true;
}
int main()
{
    char vertex[MAX];
    int num, edge;

    cin >> num >> edge;
    for (int i = 0; i < num; i++)
    {
        vertex[i] = i + '0';
    }
    ALGraph graph(vertex, num, edge);
    graph.inputEdges();
    //graph.display();
    if (!graph.GriticalPath())
    {
        cout << "存在环,无关键路径。";
    }

    // 自动调用析构函数释放程序
    return 0;
}

/*二叉树前序、中序、后序、层序遍历*/
#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
struct BiNode
{
    char data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};

class BiTree {
private:
    BiNode* root;              //指向根结点的头指针
public:
    BiTree()
    {
        root = creat(root);//调函数构建二叉树
    }
    ~BiTree() {
        release(root);
    }
    BiNode* getRoot() { return root; }
    BiNode* creat(BiNode* bt); //构造函数调用
    void release(BiNode* bt);  //析构函数调用,释放树的存储空间
    void preOrder(BiNode* bt); //前序遍历函数调用
    void inOrder(BiNode* bt);  //中序遍历函数调用
    void postOrder(BiNode* bt);//后序遍历函数调用
    void leverOrder(BiNode* bt);//层序遍历函数调用
};

//前序构建二叉树
BiNode* BiTree::creat(BiNode* bt)
{
    char ch;
    cin >> ch;

    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new BiNode;
        bt->data = ch;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);
    }
    return bt;
}

//前序遍历
void BiTree::preOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        cout << bt->data;
        preOrder(bt->lchild);
        preOrder(bt->rchild);
    }
}

//中序遍历
void BiTree::inOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        inOrder(bt->lchild);
        cout << bt->data;
        inOrder(bt->rchild);
    }
}

//后序遍历
void BiTree::postOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        postOrder(bt->lchild);
        postOrder(bt->rchild);
        cout << bt->data;
    }
}
//层序遍历
void BiTree::leverOrder(BiNode* bt)
{
    BiNode* q;
    queue<BiNode*> Q;
    Q.push(root);
    if (root == NULL)
        return;
    while (!Q.empty())
    {
        q = Q.front();
        cout << q->data;
        Q.pop();
        if (q->lchild != NULL)
            Q.push(q->lchild);
        if (q->rchild != NULL)
            Q.push(q->rchild);
    }
}

//析构函数
void BiTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        // cout<<"delete "<<bt->data<<endl;
        delete bt;
    }
}

int main()
{
    cout << "输入前序字符串:";
    BiTree tree;
    cout << "前序遍历二叉树" << endl;
    tree.preOrder(tree.getRoot());
    cout << endl;
    cout << "中序遍历二叉树" << endl;
    tree.inOrder(tree.getRoot());
    cout << endl;
    cout << "后序遍历二叉树" << endl;
    tree.postOrder(tree.getRoot());
    cout << endl;
    cout << "层序遍历二叉树" << endl;
    tree.leverOrder(tree.getRoot());
    tree.release(tree.getRoot());
    return 0;
}

/*从下至上按层遍历二叉树*/
#include<iostream>
#include<stdio.h>
#include<queue>
#include<stack>
using namespace std;

struct BiNode
{
    char data;//数据域
    BiNode* lchild, * rchild;//左右儿子指针
};
struct QNode
{
    BiNode* pNode;
    int levelNum; //记录当前层数
};

class BiTree {
private:
    BiNode* root;              //指向根结点的头指针
public:
    BiTree()
    {
        root = creat(root);//调函数构建二叉树
    }
    ~BiTree() {
        release(root);
    }
    BiNode* getRoot() { return root; }
    BiNode* creat(BiNode* bt); //构造函数调用
    void release(BiNode* bt);  //析构函数调用,释放树的存储空间

    void reverseLeverOrder(BiNode* bt);//层序遍历函数调用
    void leverOrder(BiNode* bt);
};

//前序构建二叉树
BiNode* BiTree::creat(BiNode* bt)
{
    char ch;
    cin >> ch;

    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new BiNode;
        bt->data = ch;
        bt->lchild = creat(bt->lchild);
        bt->rchild = creat(bt->rchild);
    }
    return bt;
}

//层序遍历
void BiTree::reverseLeverOrder(BiNode* bt)
{
    BiNode* q;
    queue<BiNode*> Q;
    stack<char> R;
    Q.push(root);
    if (root == NULL)
        return;
    while (!Q.empty())
    {
        q = Q.front();
        R.push(q->data);
        Q.pop();
        //先压入右子树,再压入左子树
        if (q->rchild != NULL)
            Q.push(q->rchild);
        if (q->lchild != NULL)
            Q.push(q->lchild);
    }
    while (!R.empty())
    {
        cout << R.top() << " ";
        R.pop();
    }
}

//析构函数
void BiTree::release(BiNode* bt)
{
    if (bt != NULL)
    {
        release(bt->lchild);
        release(bt->rchild);
        // cout<<"delete "<<bt->data<<endl;
        delete bt;
    }
}
//层序遍历
void BiTree::leverOrder(BiNode* bt)
{
    BiNode* q;
    queue<BiNode*> Q;
    Q.push(root);
    if (root == NULL)
        return;
    while (!Q.empty())
    {
        q = Q.front();
        cout << q->data;
        Q.pop();
        if (q->lchild != NULL)
            Q.push(q->lchild);
        if (q->rchild != NULL)
            Q.push(q->rchild);
    }
}

int main()
{
    cout << "输入前序字符串:";
    BiTree tree;
    cout << "层序遍历二叉树" << endl;
    //tree.leverOrder(tree.getRoot()); cout << endl;
    tree.reverseLeverOrder(tree.getRoot());

    tree.release(tree.getRoot());
    return 0;
}

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大一c语言期末考试试题及答案汇总 一、选择题(共10题,每题2分,共20分) 1. 下列哪个不是C语言中的数据类型? A)int B)float C)string D)char 答案:C)string 2. 下列哪个不是C语言中的控制语句? A)if B)while C)repeat D)for 答案:C)repeat 3. 下列哪个不是C语言中的逻辑运算符? A)&& B)|| C)! D)** 答案:D)** 4. 下列哪个不是C语言中的关系运算符? A)> B)< C)= D)>= 答案:C)= 5. 在C语言中,如何声明一个整型变量? A)integer x; B)int x; C)x : integer; D)x = int; 答案:B)int x; 6. 在C语言中,如何实现条件语句的多分支选择? A)if...else B)switch...case C)while D)for 答案:B)switch...case 7. 在C语言中,如何实现循环结构? A)if B)switch C)for D)else 答案:C)for 8. 下列哪个不是C语言中的赋值运算符? A)= B)+= C)== D)-= 答案:C)== 9. 在C语言中,如何定义一个字符串变量? A)string s; B)s : string; C)char s[]; D)char[] s; 答案:C)char s[]; 10. C语言程序的入口函数是? A)Main B)main C)start D)begin 答案:B)main 二、填空题(共5题,每题4分,共20分) 1. 在C语言中,用于输入数据的函数是__________。 答案:scanf 2. 在C语言中,用于输出数据的函数是__________。 答案:printf 3. 在C语言中,用于进行整数除法的运算符是__________。 答案:/ 4. 下面关系运算符中表示“大于等于”的是__________。 答案:>= 5. 在C语言中,用于声明一个字符型变量的关键字是__________。 答案:char 三、编程题(共2题,每题30分,共60分) 1. 编写一个C语言程序,实现输入两个整数,然后输出它们的和。 答案:代码略 2. 编写一个C语言程序,实现输出1到100之间所有能被3整除的数字。 答案:代码略 以上就是大一C语言期末考试的试题及答案汇总。希望同学们能够认真复习,顺利通过考试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值