LOADING

加载过慢请开启缓存 浏览器默认开启

C++数据结构与算法实验 (华科)

这篇文章是把之前发表在CSDN上面的一些东西搬运过来,是本科时候做的一些C++实验。
主要有以下几个实验:

面向过程的整型队列

面向对象的整型队列

面向对象的整形栈(双队列模拟)

面向对象的矩阵运算

弗洛伊德算法实验

1 C++实验一:面向过程的整型队列

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include<malloc.h>
struct Queue {
    int* const  elems;	   	//elems申请内存用于存放队列的元素
    const  int  max;	  	//elems申请的最大元素个数max
    int   head, tail;	 	//队列头head和尾tail,队空head=tail;初始head=tail=0
};
void initQueue(Queue* const p, int m);	//初始化p指队列:最多申请m个元素
void initQueue(Queue* const p, const Queue& s); //用s深拷贝初始化p指队列
void initQueue(Queue* const p, Queue&& s); //用s移动初始化p指队列
int  number(const Queue* const p);	//返回p指队列的实际元素个数
int  size(const Queue* const p);			//返回p指队列申请的最大元素个数max
Queue* const enter(Queue* const p, int e);  //将e入队列尾部,并返回p
Queue* const leave(Queue* const p, int& e); //从队首出元素到e,并返回p
Queue* const assign(Queue* const p, const Queue& q); //深拷贝赋s给队列并返回p
Queue* const assign(Queue* const p, Queue&& q); //移动赋s给队列并返回p
char* print(const Queue* const p, char* s);//打印p指队列至s并返回s
void destroyQueue(Queue* const p);	 //销毁p指向的队列
void initQueue(Queue* const p, int m) {
    if (p == nullptr){
        throw"The pointer must have allocated memory!";
        return;
    }
    (int&)p->max = m; //强制类型转换为可写的指针
    (int*&)p->elems = new int[m];
    //*(int**)&(p->elems) = new int[m]; 这两种写法一样
    // 相当于把只读的指针变量,强制转换为可写的指针变量
    //cout << p->max << endl;
    p->head = 0;
    p->tail = 0;
}

void initQueue(Queue* const p, const Queue& s) {
    //深拷贝的核心是:拷贝的内存块不要共用
    if (p == nullptr){
        throw"The pointer must have allocated memory!";
        return;
    }   
    p->head = s.head;
    p->tail = s.tail;
    (int&)p->max = s.max;
    (int*&)p->elems = new int[s.max];
    //初始化p
    int i = s.head;
    while (i != s.tail) {
        //当i指向数组头时,说明已经复制完毕
        p->elems[i] = s.elems[i];
        i++;
        i = i % p->max;
    }
    //深拷贝完成
}

void initQueue(Queue* const p, Queue&& s) {
    //核心是两个对象用同一个内存块,相当于把前一个对象的内存块移动走了
    if (p == nullptr){
        throw"The pointer must have allocated memory!";
        return;
    }
    if (p == &s) {
        throw"Can't init a queue which is already inited!";
        return;
    }
    p->head = s.head;
    p->tail = s.tail;
    (int&)p->max = s.max;
    //构造p
    (int*&)p->elems = s.elems;
    //内存移动
    (int *&)s.elems = nullptr;
    s.head = 0;
    s.tail = 0;
    (int&)s.max = 0;
    //处理s
}

int  number(const Queue* const p) {
    if (p->elems == nullptr)return NULL;//防止出现已经析构的队列访问number
    int head = p->head;
    int tail = p->tail;
    int max = p->max;
    return (tail - head + max) % max;
}

int  size(const Queue* const p) {
    return p->max;
}

Queue* const enter(Queue* const p, int e) {
    int head = p->head;
    int tail = p->tail;
    //cout << number(p)<<endl;
    //cout << p->max << endl;
    if ((tail+1) % p->max == head) {
        throw"Queue is full!";
        return p;
    }
    p->elems[tail] = e;
    p->tail = (p->tail+1) % (p->max);
    //改变的时候都要确保不会出现访问到数组外
    return p;
}

Queue* const leave(Queue* const p, int& e) {
    if (p->head == p->tail) {
        throw"Queue is empty!";
        return p;
    }
    e = p->elems[p->head];
    p->head = (p->head+1) % (p->max);
    return p;
}

Queue* const assign(Queue* const p, const Queue& q) {
    //深拷贝
    p->head = q.head;
    p->tail = q.tail;
    (int &)p->max = q.max;
    for (int i = 0; i < p->max; i++) {
        p->elems[i] = q.elems[i];
    }
    return p;
}

Queue* const assign(Queue* const p, Queue&& q) {
    //移动语义
    if (p == &q)return p;
    if (p->elems!=nullptr)delete []p->elems;
    //initQueue(p, q);
    (int*&)(p->elems) = q.elems;
    (int&)(p->max) = q.max;
    p->head = q.head;
    p->tail = q.tail;
    (int*&)(q.elems) = nullptr;
    (int&)(q.max) = 0;
    q.head = q.tail = 0;
    return p;
}

char* print(const Queue* const p, char* s) {
    if (p->max == 0) {
        throw"Can't print a nonexistent Queue!";
        return nullptr;
    }
    char* q = s;
    int i = p->head;
    while (i != p->tail) {
        if(i==p->head)sprintf(q, "%d", p->elems[i]);//第一个不能加(+strlen(q))否则会出现烫烫烫烫
        else sprintf(q+strlen(q), "%d", p->elems[i]);//向s字符串中打印元素
        if (i!=(p->tail-1)%p->max)
        sprintf(q+strlen(q), ",");//向s字符串中打印逗号
        i++;
        if (i == p->max) i = 0;//下标回传
    }//会自动打印'\0'的,不需要再额外添加
    return s;
}

void destroyQueue(Queue* const p) {
    if (p->elems != nullptr) {
        delete[]p->elems;
        (int*&)p->elems = nullptr;
        (int &)p->max = 0;
    }
    else throw"Can't deconstruct an invild queue!";
}

2 c++实验二:面向对象的整形队列

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <string.h>
class QUEUE {
    int* const  elems;	//elems申请内存用于存放队列的元素
    const  int  max;	//elems申请的最大元素个数为max
    int   head, tail;	 	//队列头head和尾tail,队空head=tail;初始head=tail=0
public:
    QUEUE(int m);		//初始化队列:最多申请m个元素
    QUEUE(const QUEUE& q); 			//用q深拷贝初始化队列
    QUEUE(QUEUE&& q)noexcept;		//用q移动初始化队列
    virtual operator int() const noexcept;	//返回队列的实际元素个数
    virtual int size() const noexcept;		//返回队列申请的最大元素个数max
    virtual QUEUE& operator<<(int e);  	//将e入队列尾部,并返回当前队列
    virtual QUEUE& operator>>(int& e); 	//从队首出元素到e,并返回当前队列
    virtual QUEUE& operator=(const QUEUE& q);//深拷贝赋值并返回被赋值队列
    virtual QUEUE& operator=(QUEUE&& q)noexcept;//移动赋值并返回被赋值队列
    virtual char* print(char* s) const noexcept;//打印队列至s并返回s
    virtual ~QUEUE();	 					//销毁当前队列
};
QUEUE::QUEUE(int m):max(m),head(0),tail(0),elems(new int [m]){}

QUEUE::QUEUE(const QUEUE& q) : max(q.max), head(q.head), tail(q.tail), elems() {
    (int *&)elems = new int[max];
    for (int i = 0; i < max; i++) {
        elems[i] = q.elems[i];
    }
}

QUEUE::QUEUE(QUEUE&& q)noexcept :max(q.max), head(q.head), tail(q.tail),elems(){
    if (this == &q) {
        throw"Can't init an alive QUEUE!";
        return;
    }
    (int*&)this->elems = q.elems;
    //处理源队列q
    (int *&)q.elems = 0;
    (int&)q.max = 0;
    q.head = q.tail = 0;
}

QUEUE::operator int() const noexcept {
    if (elems == nullptr)return NULL;//防止出现已经析构的队列访问number
    return (tail - head + max) % max;
}

int QUEUE::size() const noexcept {
    return max;
}

QUEUE& QUEUE::operator<<(int e) {
    if ((tail + 1) % max == head) {
        throw"QUEUE is full!";
        return *this;
    }
    elems[tail] = e;
    tail = (tail + 1) % max;
    //改变的时候都要确保不会出现访问到数组外
    return *this;
}

QUEUE& QUEUE::operator>>(int& e) {
    if (head == tail) {
        throw"QUEUE is empty!";
        return *this;
    }
    e = elems[head];
    head = (head + 1) % max;
    return *this;
}

QUEUE& QUEUE::operator=(const QUEUE& q) {
    head = q.head;
    tail = q.tail;
    (int &)max = q.max;
    for (int i = 0; i < max; i++) {
        elems[i] = q.elems[i];
    }
    return *this;
}

QUEUE& QUEUE::operator=(QUEUE&& q)noexcept {
    //移动语义
    if (this == &q)return *this;
    if (elems != nullptr)delete []elems;
    (int*&)(elems) = q.elems;
    (int&)(max) = q.max;
    head = q.head;
    tail = q.tail;
    (int*&)(q.elems) = nullptr;
    (int&)(q.max) = 0;
    q.head = q.tail = 0;
    return *this;
}

char* QUEUE::print(char* s)const noexcept {
    if (max == 0) {
        return nullptr;
    }
    char* q = s;
    int i = head;
    while (i != tail) {
        if (i == head)sprintf(q, "%d", elems[i]);
        else sprintf(q + strlen(q), "%d", elems[i]);//向s字符串中打印元素
        if (i != (tail - 1) % max)
            sprintf(q + strlen(q), ",");//向s字符串中打印逗号
        i++;
        if (i == max) i = 0;//下标回传
    }
    return s;
}

QUEUE::~QUEUE() {
    if (elems != nullptr) {
        delete[]elems;
        (int*&)elems = nullptr;
        (int&)max = 0;
    }
}

3 c++实验三:面向对象的整形栈(双队列模拟)

要用双队列模拟整型栈,需要用到整型队列作为父类:队列实现程序

栈实现程序(子类)👇

#pragma once
#include"队列父类"//请自行替换
class STACK : public QUEUE {
    QUEUE q;
public:
    STACK(int m);                    		//初始化栈:最多存放2m-2个元素
    STACK(const STACK& s);         		//用栈s深拷贝初始化栈
    STACK(STACK&& s)noexcept;     		//用栈s移动拷贝初始化栈
    int  size()const noexcept;		  		//返回栈的容量即2m
    operator int() const noexcept;	   		//返回栈的实际元素个数
    STACK& operator<<(int e); 	     		//将e入栈,并返回当前栈
    STACK& operator>>(int& e);     		//出栈到e,并返回当前栈
    STACK& operator=(const STACK& s);	//深拷贝赋值并返回被赋值栈
    STACK& operator=(STACK&& s)noexcept;//移动赋值并返回被赋值栈
    char* print(char* b)const noexcept;	//从栈底到栈顶打印栈元素 
    ~STACK()noexcept;	              	//销毁栈
};

STACK::STACK(int m):q(m),QUEUE(m){}

STACK::STACK(const STACK& s):q(s.q),QUEUE(s){}

STACK::STACK(STACK&& s)noexcept :q((QUEUE &&)s.q),QUEUE((QUEUE &&)s){}

int  STACK::size()const noexcept {
    return 2 * q.size();
}

STACK::operator int() const noexcept {
    int first, second;
    first = q.QUEUE::operator int();
    second = QUEUE::operator int();
    return first+second;
}

STACK& STACK::operator<<(int e){
    if (this->operator int() >= this->size() - 2) { 
        throw"STACK is full!";
        return *this;
    }
    if (this->QUEUE::operator int()>=this->QUEUE::size()-1) {
        //如果this 满。直接插入q
        q.QUEUE::operator<<(e);
        return *this;
    }
    this->QUEUE::operator <<(e);
    return *this;
}

STACK& STACK::operator>>(int& e) {
    QUEUE* live = this;
    if (this->operator int() == 0) { 
        throw"STACK is empty!";
        return *this;
    }
    if (q.QUEUE::operator int() != 0) {
        live = &q;
    }
    for (int i = 0; i < live->QUEUE::operator int()-1; i++) {
        int temp;
        live->QUEUE::operator>>(temp);
        live->QUEUE::operator<<(temp);
    }
    live->QUEUE::operator>>(e);
    return *this;
}

STACK& STACK::operator=(const STACK& s) {
    this->QUEUE::operator=(s);
    q.QUEUE::operator=(s.q);
    return *this;
}

STACK& STACK::operator=(STACK&& s)noexcept {
    this->QUEUE::operator=((QUEUE&&)s);
    q.QUEUE::operator=((QUEUE&&)s.q);
    return *this;
}

char* STACK::print(char* b)const noexcept {
    if (this->operator int() == 0) { 
        b[0] = '\0';
        return b; 
    }
    if (q.QUEUE::operator int() == 0) {
        this->QUEUE::print(b);
        return b;
    }
    else if(this->QUEUE::operator int() == 0){
        q.QUEUE::print(b);
        return b;
    }
    else if (q.QUEUE::size() - 1 <= q.QUEUE::operator int()) {
        char s[1024];
        q.QUEUE::print(s);
        this->QUEUE::print(b);
        sprintf(b + strlen(b), ",");
        strcat(b, s);
        return b;
    }
    else {
        char s[1024];
        q.QUEUE::print(b);
        this->QUEUE::print(s);
        sprintf(b + strlen(b), ",");
        strcat(b, s);
        return b;
        
    }
}
STACK::~STACK()noexcept {}

4 c++实验四:面向对象的矩阵运算

#pragma once
#define _CRT_SECURE_NO_WARNINGS 
#include <iomanip> 
#include <exception>
#include <typeinfo>
#include <string.h>
template <typename T>
class MAT {
    T* const e;							//指向所有整型矩阵元素的指针
    const int r, c;							//矩阵的行r和列c大小
public:
    MAT(int r, int c);						//矩阵定义
    MAT(const MAT& a);				//深拷贝构造
    MAT(MAT&& a)noexcept;			//移动构造
    virtual ~MAT()noexcept;
    virtual T* const operator[ ](int r);//取矩阵r行的第一个元素地址,r越界抛异常
    virtual MAT operator+(const MAT& a)const;	//矩阵加法,不能加抛异常
    virtual MAT operator-(const MAT& a)const;	//矩阵减法,不能减抛异常
    virtual MAT operator*(const MAT& a)const;	//矩阵乘法,不能乘抛异常
    virtual MAT operator~()const;					//矩阵转置
    virtual MAT& operator=(const MAT& a);		//深拷贝赋值运算
    virtual MAT& operator=(MAT&& a)noexcept;	//移动赋值运算
    virtual MAT& operator+=(const MAT& a);		//“+=”运算
    virtual MAT& operator-=(const MAT& a);		//“-=”运算
    virtual MAT& operator*=(const MAT& a);		//“*=”运算
//print输出至s并返回s:列用空格隔开,行用回车结束
    virtual char* print(char* s)const noexcept;
};

template <typename T>
MAT<T>::MAT(int r, int c) :r(r), c(c), e(nullptr) {
    (T*&)e = new T[r * c];
}

template <typename T>
MAT<T>::MAT(const MAT& a) : r(a.r), c(a.c),e(nullptr) {
    //if (*this == a) {
    //	throw"错误";
    //	return;
    //}
    (T*&)e = new T[r * c];
    //不要在参数表中分配内存,要首先保证之前的指针是空指针
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            this->e[i * c + j] = a.e[i * c + j];
        }//深拷贝赋值
    }
}

template<typename T>
MAT<T>::MAT(MAT&& a)noexcept :r(a.r), c(a.c), e() {
    
    (T*&)e = a.e;//移动赋值
    //析构a
    (T*&)a.e = nullptr;
    (int&)a.r = 0;
    (int&)a.c = 0;
}

template<typename T>
MAT<T>::~MAT()noexcept {
    //printf("析构函数被调用\n");
    if (this->e!=nullptr)delete[]e;
    (T*&)e = nullptr;
    //只需要显式写出new分配的内存
}

template<typename T>
T* const MAT<T>::operator[](int r) {
    if (r >= this->r) {
        throw"数组越界";
        return nullptr;
    }
    return &(e[r * c]);//返回第r行第一个元素地址
}

template<typename T>
MAT<T> MAT<T>::operator+(const MAT& a)const {
    //矩阵加法要保证行列相等才能相加
    //printf("矩阵加法被调用\n");
    if (a.r != r || a.c != c) {
        throw"error";
        return *this;
    }
    MAT<T> temp(r, c);
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            temp[i][j] = e[i * c + j] + a.e[i * c + j];
        }
    }
    //printf("+被调用\n");
    return temp;
}

template<typename T>
MAT<T> MAT<T>::operator-(const MAT& a)const {
    //矩阵减法要保证行列相等才能相加
    //printf("矩阵减法被调用\n");
    if (a.r != r || a.c != c) {
        throw"error";
        return *this;
    }
    MAT<T> temp(r, c);
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            temp[i][j] = e[i * c + j] - a.e[i * c + j];
        }
    }
    //printf("-被调用\n");
    return temp;
}

template<typename T>
MAT<T> MAT<T>::operator*(const MAT& a)const {
    //printf("矩阵乘法被调用\n");
    //printf("a:\n");
    /*for (int i = 0; i < a.r; i++) {
        for (int j = 0; j < a.c; j++) {
            printf("%d,", a.e[i * c + j]);
        }
        printf("\n");
    }
    printf("this:\n");
    for (int i = 0; i < this->r; i++) {
        for (int j = 0; j < this->c; j++) {
            printf("%d,", this->e[i * c + j]);
        }
        printf("\n");
    }*/
    //if (a.r == 0 || r == 0) { return *this; }
    if (c != a.r) {
        throw"行列数不匹配,无法相乘";
        return *this;
    }
    MAT<T> temp(r, a.c);
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < a.c; j++) {
            temp.e[i * a.c + j] = 0;
            for (int k = 0; k < a.c; k++) {
                temp.e[i * a.c + j] += e[i * a.c + k] * a.e[k * r + j];
            }
        }
    }
    /*printf("temp:\n");
    for (int i = 0; i < temp.r; i++) {
        for (int j = 0; j < temp.c; j++) {
            printf("%d,", temp[i][j]);
        }
        printf("\n");
    }*/
    return temp;
}

template <typename T>
MAT<T> MAT<T>::operator~()const {
    //printf("矩阵转置被调用\n");
    if (r == 0 || c == 0) {
        return *this;
    }
    MAT<T> temp(c, r);
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            temp.e[j * r + i] = e[i * c + j];
        }
    }
    return temp;
}

template<typename T>
MAT<T>& MAT<T>::operator=(const MAT& a) {
    //printf("矩阵拷贝赋值被调用\n");
    if (e == a.e) {
        return *this;
    }
    if (this->e)delete[]e;
    (T*&)e = new T[r * c];
    (int&)r = a.r;
    (int&)c = a.c;
    //重新构造新的矩阵
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            this->e[i * c + j] = a.e[i * c + j];
        }
    }
    return *this;
}

template<typename T>
MAT<T>& MAT<T>::operator=(MAT&& a)noexcept {
    //printf("矩阵移动赋值被调用\n");
    if (this->e == a.e) {
        return *this;
    }
    if (this->e)delete[]e;
    (int&)r = a.r;
    (int&)c = a.c;
    (T*&)e = a.e;
    //析构原始矩阵
    (T*&)a.e = nullptr;
    (int&)a.r = (int&)a.c = 0;
    return *this;
}

template<typename T>
MAT<T>& MAT<T>::operator+=(const MAT& a) {
    //矩阵加法要保证行列相等才能相加
    //printf("矩阵+=被调用\n");
    if (a.r != r || a.c != c) {
        throw"error";
        return *this;
    }
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            e[i * c + j] += a.e[i * c + j];
        }
    }
    return *this;
}

template<typename T>
MAT<T>& MAT<T>::operator-=(const MAT& a) {
    //矩阵减法要保证行列相等才能相加
    //printf("矩阵-=被调用\n");
    if (a.r != r || a.c != c) {
        throw"error";
        return *this;
    }

    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            e[i * c + j] -= a.e[i * c + j];
        }
    }
    return *this;
}

template<typename T>
MAT<T>& MAT<T>::operator*=(const MAT& a) {
    //printf("矩阵*=被调用\n");
    if (this->c != a.r) {
        throw"行列数不匹配,无法相乘";
        return *this;
    }
    MAT<T> temp(r, a.c);
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < a.c; j++) {
            temp.e[i * a.c + j] = 0;
            for (int k = 0; k < a.c; k++) {
                temp.e[i * a.c + j] += e[i * a.c + k] * a.e[k * r + j];
            }
        }
    }
    //移动赋值给this
    //printf("%d,%d\n", temp.r, a.r);
    this->operator=((MAT<T>&&)temp);
    /*if (this->e)delete[]e;
    (int&)r = a.r;
    (T*&)e = temp.e;
    //析构原始矩阵
    (T*&)temp.e = nullptr;
    (int&)temp.r = (int&)temp.c = 0;
    */
    //printf("%d\n",a.r);
    return *this;
}

template<>
char* MAT<_int64>::print(char* s)const noexcept {
    //printf("矩阵打印被调用\n");
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            if (i + j == 0)sprintf(s, "%d ", e[i * c + j]);
            else sprintf(s + strlen(s), "%d ", e[i * c + j]);
        }
        sprintf(s + strlen(s), "\n");
    }
    return s;
}

template<>
char* MAT<
    int>::print(char* s)const noexcept {
    //printf("矩阵打印被调用\n");
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            if (i + j == 0)sprintf(s, "%d ", e[i * c + j]);
            else sprintf(s + strlen(s), "%d ", e[i * c + j]);
        }
        sprintf(s + strlen(s), "\n");
    }
    return s;
}

template<>
char* MAT<long>::print(char* s)const noexcept {
    //printf("矩阵打印被调用\n");

    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            if (i + j == 0)sprintf(s, "%f ", e[i * c + j]);
            else sprintf(s + strlen(s), "%f ", e[i * c + j]);
        }
        sprintf(s + strlen(s), "\n");
    }
    return s;
}

5 C++实验5:弗洛伊德算法实验

弗洛伊德算法解析见弗洛伊德算法

采用邻接矩阵存储图,矩阵的行和列为图的节点,矩阵的内容为图的权重。

//#pragma comment(linker,"/STACK:614400000,614400000") 
//在运行PRINT_ALL_PAIRS_SHORTEST_PATH的时候如果发生stack overflow,请使用上一行的语句扩展栈
#define INF 999999999//无穷大定义
#define NIL -1//Pi矩阵的不可达定义
#define _CRT_SECURE_NO_DEPRECATE
#define frow 11484 //这里是我的图的行数,改成自己图的行数即可
#define N 1000 //这是我节点的数量,改成自己节点的数量即可
#include <iostream>
#include<fstream>
#include<stdio.h>
#include<string>
using namespace std;
int* read(string filename, int n) {
    ifstream fp(filename, ios::in);
    int p1, p2, weight; //数据缓冲区
    int *MAT = new int[n * n];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            MAT[i * n + j] = INF;
            if (i == j)MAT[i * n + j] = 0;
        }
    }
    if (!fp) {  // 判断文件是否存在
        cerr << "open error." << endl;
        return nullptr;
    }
    for (int i = 0; i < frow; i++) {
        fp >> p1;
        fp >> p2;
        fp >> weight;
        //cout << p1 << " " << p2 << " " << weight << endl;
        if (p1 < 0 || p1>1000 || p2 < 0 || p2>1000) {
            throw"读取数据错误";
        }
        MAT[p1 * n + p2] = weight;
    }
    return MAT;
}
void write(string filename, int* MAT,int n) {
    ofstream fout(filename, ios::out);
    if (!fout) {  // 判断文件是否存在
        cerr << "open error." << endl;
        //exit(1); // 退出程序
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++){
            if (MAT[i * n + j] == INF)fout << "INF" << ",";
            else fout << MAT[i * n + j] << ",";
        }
        fout << endl;
    }
    fout.close();
}
void print(int *D, int n) {
    //打印矩阵
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (D[i * n + j] == INF)cout << "INF ";
            else
                cout << D[i*n+j]<<"  ";
        }
        cout << endl;
    }
}
int** FLOYD_WARSHALL(int* W, int n) {
    int* D;
    int* PI;
    int** res = new int* [2];
    D = new int [n*n];
    PI = new int[n * n];
    res[0] = D;
    res[1] = PI;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (W[i * n + j] == INF || i == j)PI[i * n + j] = NIL;
            else PI[i * n + j] = i;
            D[i * n + j] = W[i * n + j];
        }
    }//初始化D矩阵

    for (int k = 0; k < n; k++)
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (D[i * n + j] > D[i * n + k] + D[k * n + j]) {
                    PI[i * n + j] = PI[k * n + j];
                    D[i * n + j] = D[i * n + k] + D[k * n + j];
                }
            }
        }
        printf("正在运算%d/%d\r", k+1,n);
    }
    return res;
}

void PRINT_ALL_PAIRS_SHORTEST_PATH(int *PI,int i,int j) {
    if (i == j) {
        cout << i<<" ";
    }
    else if (PI[i*N+j] == NIL) {
        cout << "No path from " << i << " to " << j << " exits" << endl;
    }
    else
    {
        PRINT_ALL_PAIRS_SHORTEST_PATH(PI, i, PI[i * N + j]);
        cout << j<<" ";
    }
}

int main() {
    /*int W[25] = { 0  ,3  ,8  ,INF,-4,INF,0  ,INF,1  ,7  ,INF,4  ,0  ,INF,INF,2  ,INF,-5 ,0  ,INF,INF,INF,INF,6  ,0  };
    //print(W,5);
    //cout << endl;
    int** res;
    res = FLOYD_WARSHALL(W, 5);
    print(res[0], 5);
    cout << endl;
    print(res[1], 5);
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            cout << "从" << i << "到" << j << "的最短路径为:" << endl;
            PRINT_ALL_PAIRS_SHORTEST_PATH(res[1], i, j, 5);
            cout << endl;
        }
    }
    delete[]res;*/
    /*ifstream fp("weight_graph.txt", ios::in);
    string buff;
    int p1, p2, weight; //数据缓冲区
    int* W = new int[N*N];
    int** res;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            W[i * N + j] = INF;
            if (i == j)W[i * N + j] = 0;
        }
    }
    if (!fp) {  // 判断文件是否存在
        cerr << "open error." << endl;
        return 1;
    }
    for (int i = 0; i < 11484; i++) {
        for (int j = 0; j < 3; j++) {
            if (j == 0)fp >> p1;
            else if (j == 1)fp >> p2;
            else fp >> weight;
        }
        //cout << p1 << " " << p2 << " " << weight << endl;
        W[p1 * N + p2] = weight;
    }
    */
    int* W;
    int** res;
    W = read("weight_graph.txt", N);
    res = FLOYD_WARSHALL(W,N);
    //for (int i = 0; i < N; i++) {
        //for (int j = 0; j < N; j++) {
            //PRINT_ALL_PAIRS_SHORTEST_PATH(res[1], i, j);
            //cout << endl;
        //}
    //}
    cout << "正在存储D矩阵" << endl;
    write("D-result.txt", res[0],N);
    cout << "D矩阵存储完成" << endl;
    cout << "正在存储Pi矩阵" << endl;
    write("Pi-result.txt", res[1], N);
    cout << "Pi矩阵存储完成" << endl;
    if (W != nullptr) {
        delete[]W;
    }
    if (res != nullptr) {
        delete[]res;
    }
    /*ofstream dout("D-result.txt", ios::out);
    ofstream pout("Pi-result.txt", ios::out);
    string D;
    string Pi;
    if (!dout) {  // 判断文件是否存在
        cerr << "open error." << endl;
        //exit(1); // 退出程序
    }
    if (!pout) {  // 判断文件是否存在
        cerr << "open error." << endl;
        //exit(1); // 退出程序
    }
    dout << result[0];
    dout << result[1];
    fp.close();
    dout.close();
    pout.close();*/
    return 0;
}