zoukankan      html  css  js  c++  java
  • C++实现树和链表

    一、背景

    为了方便以后的复习,这里记录一下树和链表的过程。

    二、基础概念

    树:左子树,右子树,根节点(逻辑结构)

    链表:表头,数据(物理结构)

     两种结构的区别

    从大的方面来说,数据结构是反映数据的一种形式,它具体分为逻辑结构和物理结构,
    1,逻辑结构:它是表现数据之间的一种关系的结构,分为线性结构和非线性结构;
    2,物理结构:它是表现数据的是如何存储的结构,计算机内部是如何安排该数据的存储,通常分为顺序结构,链式结构,索引结构,哈希结构;

    实现过程

     空间结构

    三、实现

    3.1 链表

    定义头文件

    #ifndef FIRST_NODEOP_H
    #define FIRST_NODEOP_H
    
    
    class Node1 {
    public:
        int data{};  // 数据
        Node1 *next = nullptr;  // 移动和寻找的结构体指针
    
        static void outAllList(Node1 *node1); // 遍历所有结果
        static void addTail(Node1 *node1, int value);  // 尾插法
        static void addHead(Node1 *node1, int value);  // 头插法
        static char searchOne(Node1 *node1, int value);  // 查找
        static void deleteOne(Node1 *node1, int value);  // 删除
    };
    
    #endif //FIRST_NODEOP_H

    使用c++的资源文件

    #include "nodeop.h"
    #include <iostream>
    
    using namespace std;
    
    int main() {
        // 使用auto避免重复生成对象名字  和使用Node1 *head = new Node1等效
        auto *head = new Node1;  //  头节点的声明
        head->data = 1;
        auto *first = new Node1;  // 创建第一个节点
        first->data = 2;
        head->next = first;  // 头结点和第一个节点相连接
        auto *second = new Node1; //创建第二个节点
        second->data = 10;
        first->next = second;  // 第一个节点和第二个相连
        Node1::addTail(head, 11); // 插入节点
        Node1::addTail(head, 12); // 插入节点
        Node1::addTail(head, 17); // 插入节点
        Node1::addHead(head, 13); // 插入节点
        Node1::addHead(head, 14); // 插入节点
        Node1::addHead(head, 15); // 插入节点
        Node1::outAllList(head);
        cout << Node1::searchOne(head, 30) << endl;
        cout << Node1::searchOne(head, 2) << endl;
        Node1::deleteOne(head, 17); // 删除节点
        Node1::outAllList(head);  // 遍历结果
    }
    
    void Node1::outAllList(Node1 *head) {
        while (head != nullptr) { // 遍历结果
            cout << head->data << " ";
            head = head->next;
        }
    }
    
    void Node1::addTail(Node1 *node1, int value) {
        while (node1->next != nullptr) {  // 找到指针的最后节点,插入数据
            node1 = node1->next;
        }
        auto *newNode = new Node1;
        newNode->data = value;
        node1->next = newNode;
    }
    
    void Node1::addHead(Node1 *node1, int value) {
        if (node1->next == nullptr) {
            auto *newNode = new Node1;
            newNode->data = value;
            node1->next = newNode;
        } else {
            auto *newNode = new Node1;
            newNode->data = value;
            newNode->next = node1->next;
            node1->next = newNode;
        }
    
    }
    
    char Node1::searchOne(Node1 *node1, int value) {
        while (node1 != nullptr) {
            if (node1->data == value) {
                return 'y';
            }
            node1 = node1->next;
        }
        return 'n';
    
    }
    
    void Node1::deleteOne(Node1 *node1, int val) {
        Node1 *pre = node1;
        Node1 *cur = node1;
        while (cur != nullptr && cur->data != val){
            pre = cur;
            cur = cur->next;
        }
        if (cur != nullptr){
            pre->next = cur->next;
        }
    }

    3.2 树

    定义的树的头文件

    #ifndef FIRST_TREE_H
    #define FIRST_TREE_H
    struct Tree {
        int data{};
        Tree *rightTree = nullptr;
        Tree *leftTree = nullptr;
    };
    
    #endif //FIRST_TREE_H

    资源文件

    同时实现了树的深度优先遍历和广度优先遍历(和层次遍历一样)

    #include "Tree.h"
    #include <iostream>
    #include <vector>
    #include <queue>
    #include <stack>
    
    using namespace std;
    
    void mid(Tree *tree);
    
    vector<vector<int> > levelOrder(Tree *pRoot);  // 层次、广度搜索
    
    vector<int> dfs(Tree *pBoot);  // 深度
    
    int main() {
        /**
         *       5
         *    1      2
         * 3     4
         *     6   10
         */
        Tree *r7 = new Tree();
        r7->data = 10;
        Tree *r6 = new Tree();
        r6->data = 6;
        Tree *r2 = new Tree();
        r2->data = 2;
        Tree *r3 = new Tree();
        r3->data = 3;
        Tree *r4 = new Tree();
        r4->data = 4;
        r4->leftTree = r6;
        r4->rightTree = r7;
        Tree *r1 = new Tree();
        r1->data = 1;
        r1->rightTree = r4;
        r1->leftTree = r3;
        Tree *root = new Tree();
        root->data = 5;
        root->rightTree = r2;
        root->leftTree = r1;
        cout << "中序遍历:" << endl;
        mid(root);  // 中序遍历
        cout << endl;
        vector<vector<int >> nums = levelOrder(root);
        cout << "层次遍历: " << endl;
        for (auto &num : nums) {
            for (int j : num) {
                cout << j << " ";
            }
        }
        cout << endl;
        cout << "深度遍历: " << endl;
        vector<int> nums1 = dfs(root);
        for (int num:nums1) {
            cout << num << " ";
        }
    }
    
    void mid(Tree *tree) {
        // 中序遍历
        if (tree != nullptr) {
            // 后续遍历和先序遍历改变输出的位置就可了
            mid(tree->leftTree);
            cout << tree->data << " ";
            mid(tree->rightTree);
        }
    }
    
    
    vector<vector<int> > levelOrder(Tree *pRoot) {
        // 队列实现
        vector<vector<int> > res;
        if (pRoot == nullptr)
            return res;
        queue<Tree *> q;
        q.push(pRoot);
        while (!q.empty()) {
            int cnt = q.size();  // 关键:这个size可以保证逐层遍历二叉树
            vector<int> temp;
            while (cnt--) {  // 层次遍历需要查询完每一个节点
                Tree *pNode = q.front();  // 先访问到元素在进行操作
                q.pop();
                temp.push_back(pNode->data);
                if (pNode->leftTree)
                    q.push(pNode->leftTree);
                if (pNode->rightTree)
                    q.push(pNode->rightTree);
            }
            res.push_back(temp);
        }
    
        return res;
    }
    
    vector<int> dfs(Tree *pBoot) {
        // 栈实现
        vector<int> res;
        if (pBoot == nullptr)
            return res;
        stack<Tree *> s;
        s.push(pBoot);
        while (!s.empty()) {
            Tree *pNode = s.top();  // 先访问到元素 在执行操作
            s.pop();
            res.push_back(pNode->data);
            if (pNode->rightTree)  // 由于压栈所以出左边的先右压栈
                s.push(pNode->rightTree);
            if (pNode->leftTree)
                s.push(pNode->leftTree);
        }
        return res;
    }

    三、总结

    在实现的过程,回想起头指针和头结点的问题,头指针是作为链表和树的第一个位置,所以在请求内存的时候就会生成,以这个来进行操作链表、树等数据结构。

    指针移动如果没有设置另一个指针头,那么数据就会遗失,或者使用双指针来进行操作。

  • 相关阅读:
    Spring AOP概念理解 (通俗易懂)
    分享一下几个关于ssm及spring原理的专栏链接
    liux高级常用命令
    Linux基础常用命令
    SP1716 GSS3
    HDU6579 Operation
    CF1205C Palindromic Paths
    CF1213G Path Queries
    CF1213F Unstable String Sort
    CF1213E Two Small Strings
  • 原文地址:https://www.cnblogs.com/future-dream/p/14127298.html
Copyright © 2011-2022 走看看