/*波兰表达式求值*/
#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;
}