C++:十字链表的建立

见鬼了,晚上睡不着,所以就写写博客算了。
十字链表的逻辑结构如图:
这里写图片描述

两个线性表,线性表类型为十字链表节点类型(这里为了便于编写代码没有用联合体,联合体会更省空间),其中一个线性表是每一行的头结点,另一个线性表是每一列的头结点。每个节点通过指针的连接形成十字链表,图中画的不是很多,应该是如下的样子:
这里写图片描述
本次用第一张图的结构进行讲解。结构体声明如下:

//十字链表节点结构体
struct Node
{
    int i, j, v;
    Node* down, *right;
    Node() {
        i = j = v = -1;
        down = right = nullptr;
    }
    Node(int i,int j,int v) {
        this->i = i;
        this->j = j;
        this->v = v;
        down = right = nullptr;
    }
};

//十字链表结构体
struct OrthogonalList
{
    int r, c, size;
    Node**rhead, **chead;
    OrthogonalList() {
        throw logic_error("The number of row and column must be specified for the initialization of the cross linked list!");
    }

    OrthogonalList(int r, int c) {
        rhead = new Node*[r];
        chead = new Node*[c];
        for (int i = 0; i < r; i++)
            rhead[i] = new Node();
        for (int i = 0; i < c; i++)
            chead[i] = new Node();
        this->r = r;
        this->c = c;
        size = 0;
    }

    ~OrthogonalList() {
        for (int i = 0; i < r; i++)
            delete rhead[i];
        for (int i = 0; i < c; i++)
            delete chead[i];
        delete rhead;
        delete chead;
    }
};

这里十字链表节点结构体包含5个分量,分别代表行,列,值,同一行的下一个节点(*right),同一列的下一个节点(*down)。
十字链表结构体包含5个分量,rhead则代表行头结点数组,chead代表列头结点数组。r表示行数,c表示列数,size表示矩阵的内非零元素的个数。默认构造函数不允许使用,因为需要提前对rhead和chead分配空间,故需要提前传入参数行数和列数。

二维数组矩阵转化为十字链表函数:

OrthogonalList * to_orthogonalList(int ** matrix, int m, int n)
{
    OrthogonalList* r = new OrthogonalList(m, n);
    Node *p = nullptr, *q = nullptr, *s = nullptr;
    for (int i = 0; i < m; i++)
    {
        q = nullptr;
        s = nullptr;
        p = r->rhead[i];
        for (int j = 0; j < n; j++)
        {
            if (matrix[i][j] != 0)
            {
                //如果矩阵当前位置的值不为0
                r->size++;
                s = new Node(i + 1, j + 1, matrix[i][j]);
                //第一次循环和第i行头结点相连,之后的循环依次和当前最后一个节点相连
                p->right = s;
                p = p->right;
                if (r->chead[j]->down == nullptr)
                {
                    //如果第j列的down指针为空,则直接连接
                    r->chead[j]->down = s;
                }
                else
                {
                    //反之则用一个循环找到要连接的位置
                    for (q = r->chead[j]; q->down != nullptr; q = q->down);
                    q->down = s;
                }
            }
        }
    }
    return r;
}

转化过程如下:
1.通过二重循环遍历矩阵,从第1行开始找,接着是第2行,寻找非零元素。
2.用一个指针p指向对应的行的头结点。
3.申请一个新的节点吧非零元素的信息储存进去,节点指针域全部置空,讲p指针所指的头结点相连。p指向新的节点。若节点所在列的头结点没有连接节点,则直接让头结点和新的节点相连,反之则用一个循环寻找要连接的位置。
4.重复步骤3,直到一行找完,遍历下一行矩阵,回到步骤2继续执行。
5.直到矩阵全部建立完毕,返回十字链表指针。

其中第三个步骤需要分情况讨论:
1.若节点所在列的头结点没有元素,则直接相连,如图所示第一列
这里写图片描述
2.若节点所在的列的头结点已经连接了一个及以上的元素,则用循环找到列的头结点所在链表的最后一个节点连接,如图所示第五列
这里写图片描述

根据三元组表的输入方式直接建立十字链表函数:

OrthogonalList * get_orthogonalList()
{
    int m, n;
    cout << "请输入行数和列数:";
    cin >> m >> n;
    OrthogonalList* r = new OrthogonalList(m, n);
    int i, j, v;
    Node *p = nullptr, *q = nullptr;
    cin >> i >> j >> v;
    while (i != -1)
    {
        r->size++;
        q = new Node(i, j, v);
        if (r->rhead[i - 1]->right == nullptr)
            //如果第i行的头结点的right指针为空,则直接连接
            r->rhead[i - 1]->right = q;
        else
        {
            //如果第i行的头节点的right指针不为空
            //用循环要插入节点的位置
            for (p = r->rhead[i - 1]->right; p->right != nullptr&&p->right->j > j; p = p->right);
            //节点插入
            q->right = p->right;
            p->right = q;
        }
        if (r->chead[j - 1]->down == nullptr)
            //如果第j列的头结点的down指针为空,则直接连接
            r->chead[j - 1]->right = q;
        else
        {
            //如果第j列的头结点的down指针不为空
            //用循环要插入节点的位置
            for (p = r->chead[j - 1]->down; p->down != nullptr&&p->down->i > i; p = p->down);
            //节点插入
            q->down = p->down;
            p->down = q;
        }
        cin >> i >> j >> v;
    }
    return r;
}

比如我输入 1 1 2 代表第一行第一列的值为2,如此输入。由于输入可能是无序的,连接节点需要分情况:
1.当前节点所在行,列的头结点并没有连接节点,则直接相连。
2.当前节点所在行,列的头结点已经连接了一个及以上元素,则用一个循环找到要连接的位置(相应指针域为空,或者行号\列好恰好小于当前节点的节点)并连接。

完整代码如下:

#include <iostream>

using namespace std;

//十字链表节点结构体
struct Node
{
    int i, j, v;
    Node* down, *right;
    Node() {
        i = j = v = -1;
        down = right = nullptr;
    }
    Node(int i,int j,int v) {
        this->i = i;
        this->j = j;
        this->v = v;
        down = right = nullptr;
    }
};

//十字链表结构体
struct OrthogonalList
{
    int r, c, size;
    Node**rhead, **chead;
    OrthogonalList() {
        throw logic_error("The number of row and column must be specified for the initialization of the cross linked list!");
    }

    OrthogonalList(int r, int c) {
        rhead = new Node*[r];
        chead = new Node*[c];
        for (int i = 0; i < r; i++)
            rhead[i] = new Node();
        for (int i = 0; i < c; i++)
            chead[i] = new Node();
        this->r = r;
        this->c = c;
        size = 0;
    }

    ~OrthogonalList() {
        for (int i = 0; i < r; i++)
            delete rhead[i];
        for (int i = 0; i < c; i++)
            delete chead[i];
        delete rhead;
        delete chead;
    }
};

//得到矩阵
int** get_matrix();

//二维数组矩阵转化为十字链表
OrthogonalList* to_orthogonalList(int** matrix, int m, int n);

//直接按照三元组的格式建立十字链表  例如 1 1 2代表第一行,第一列的值为2
OrthogonalList* get_orthogonalList();

//打印十字链表
void print(OrthogonalList* r);



int main()
{
    print(get_orthogonalList());
    system("pause");
    return 0;
}

int ** get_matrix()
{
    int m, n;
    int** matrix = nullptr;
    cout << "请输入行数和列数:";
    cin >> m >> n;

    matrix = new int*[m];
    for (int i = 0; i < m; i++)
        matrix[i] = new int[n];

    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
            cin >> matrix[i][j];
    }
    return matrix;
}

OrthogonalList * to_orthogonalList(int ** matrix, int m, int n)
{
    OrthogonalList* r = new OrthogonalList(m, n);
    Node *p = nullptr, *q = nullptr, *s = nullptr;
    for (int i = 0; i < m; i++)
    {
        q = nullptr;
        s = nullptr;
        p = r->rhead[i];
        for (int j = 0; j < n; j++)
        {
            if (matrix[i][j] != 0)
            {
                //如果矩阵当前位置的值不为0
                r->size++;
                s = new Node(i + 1, j + 1, matrix[i][j]);
                //第一次循环和第i行头结点相连,之后的循环依次和当前最后一个节点相连
                p->right = s;
                p = p->right;
                if (r->chead[j]->down == nullptr)
                {
                    //如果第j列的down指针为空,则直接连接
                    r->chead[j]->down = s;
                }
                else
                {
                    //反之则用一个循环找到要连接的位置
                    for (q = r->chead[j]; q->down != nullptr; q = q->down);
                    q->down = s;
                }
            }
        }
    }
    return r;
}

OrthogonalList * get_orthogonalList()
{
    int m, n;
    cout << "请输入行数和列数:";
    cin >> m >> n;
    OrthogonalList* r = new OrthogonalList(m, n);
    int i, j, v;
    Node *p = nullptr, *q = nullptr;
    cin >> i >> j >> v;
    while (i != -1)
    {
        r->size++;
        q = new Node(i, j, v);
        if (r->rhead[i - 1]->right == nullptr)
            //如果第i行的头结点的right指针为空,则直接连接
            r->rhead[i - 1]->right = q;
        else
        {
            //如果第i行的头节点的right指针不为空
            //用循环要插入节点的位置
            for (p = r->rhead[i - 1]->right; p->right != nullptr&&p->right->j > j; p = p->right);
            //节点插入
            q->right = p->right;
            p->right = q;
        }
        if (r->chead[j - 1]->down == nullptr)
            //如果第j列的头结点的down指针为空,则直接连接
            r->chead[j - 1]->right = q;
        else
        {
            //如果第j列的头结点的down指针不为空
            //用循环要插入节点的位置
            for (p = r->chead[j - 1]->down; p->down != nullptr&&p->down->i > i; p = p->down);
            //节点插入
            q->down = p->down;
            p->down = q;
        }
        cin >> i >> j >> v;
    }
    return r;
}

void print(OrthogonalList * r)
{
    Node *p = nullptr, *q = nullptr;
    for (int i = 0; i < r->r; i++)
    {
        p = r->rhead[i]->right;
        for (q = p; q != nullptr; q = q->right)
            cout << q->i << "\t" << q->j << "\t" << q->v << endl;
    }
    cout << endl;
}

猜你喜欢

转载自blog.csdn.net/kongming07/article/details/80058500