一、背景

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

二、基础概念

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

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

 两种结构的区别

从大的方面来说,数据结构是反映数据的一种形式,它具体分为逻辑结构和物理结构,
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;
}

三、总结

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

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

posted on 2020-12-20 22:16  蔚蓝色の天空  阅读(474)  评论(0编辑  收藏  举报