二叉树搜索树插入,查找,删除,Key/Value二叉搜索树场景应用+源码实现

简介: 二叉搜索树(BST)是一种有序二叉树,左子树节点值小于根,右子树大于根。支持插入、查找、删除操作,平均时间复杂度为O(log n)。通过中序遍历可得有序序列。常用于实现字典、统计频次等场景,结合键值对(KV)结构可扩展应用。

二叉树的概念

二叉树搜索树又叫二叉排序树,
左边的子树都是小于根,右边的子树都是大于根.
二叉搜索树的性能分析:
最优情况下,而成二叉搜索树为完全二叉树,(或者接近完全二叉树):其高度为O(log2N)

二叉搜索树的实现;

using可以展开命名空间,也可以用来定义类型,using Node=BSTNode<K> ,就是将Node作为BSTNode<K>的别名.

template<class K>
//定义结构
struct BSTNode
{
   
    K _key;
    BSTNode<K>* _left;
    BSTNode<K>* _right;

    BSTNode(const K& key)
        :_key(key)
        ,_left(nullptr)
        ,_right(nullptr)
    {
    }
};
//用模板定义二叉搜索树的关键字,如果是大于关键字就往右边走,小于关键字就往左边走

template<class K>
class BSTree
{
   
    //typedef BSTNode<K> Node;
    using Node = BSTNode<K>;
public:
    bool Insert(const K& key)
private:
    Node* _root = nullptr;
};

二叉树的插入

这里可以使用递归,也可以使用循环.假如说需要插入的数字小于根节点,往左边走,大于根节点,就往右边走,在可以使用递归和循环的时候,我们优先选择使用循环.
定义一个cur来记录判断过程,当cur<root,执行左边的操作,然后一直走到为空的地方New一个新的节点插入,右边也是这样的逻辑.但是在申请新的节点进行插入的时候,要跟二叉树有一个链接,所以我们定义一个parent节点,

当开始走的时候,parent指向空,cur指向root节点,Node* cur=_root,当root的左右子树不为空,判断cur->val小于key,就将cur=cur->right ,在此之前更新一下parent的节点,指向cur的位置,也就是parent=cur ;cur->val大于key,cur=cur->left ,在此之前更新一下parent的节点,指向cur的位置,也就是parent=cur .去重操作,将cur->val=key的情况返回false.也可以不去重,那就要将=的这种情况插入到>或<的判断中.

接着向下判断,走到空节点就结束循环.
此时cur走到空了,向上判断此时他的位置相比parent所在的值是大于还是小于,大于parent就向右插入到parent->right中,小于parent就插入到parent->left中.

最后返回true.

bool Insert(const K& key)
{
   
    if (_root == nullptr)
    {
   
        _root = new Node(key);
        return true;
    }
    Node* cur = _root;
    Node* parent = nullptr;
    while (cur)
    {
   
        if (cur->_val < key)//如果此时cur所在的根节点的值小于要插入的key
        {
   
            parent = cur;//每次走的时候将值给parent
            cur = cur->_right;
        }
        else if(cur->_val>key)
        {
   
            parent = cur;
            cur = cur->_left;
        }
        else{
    return false; }
    }
    cur = new node(key);
    if (parent->_val < key) {
    parent->_right = cur; }
    else {
    parent->_left = cur; }
    return true;
}

插入好了之后我们用中序遍历来打印出来,中序遍历就是先将左子树部分走完之后,打印出中间的根节点,再走右子树.
代码实现一下:

private:
    void _Inorder(Node* root)
    {
   
        if(root==nullptr)
        {
   
            return;
        }
        _Inorder(root->_left);
        cout<<root->_val<<" ";
        _Inorder(root->_right);
    }

这里给一个案例数组用来测试,将数组中的数字插入到二叉搜索树中,最后用中序遍历打印出来;
注意:此时_root属于类中的私有成员,在类外面是不可以访问的,但是在类里面是可以的,所以这里我们在类中的公有部分public实现一个Inorder(),重新调用一下.;类里面二叉树的递归基本上都会用这种办法.


对二叉搜索树进行中序遍历,一定能够得到一个有序序列


public:
    void Inorder()
    {
   
        _Inorder(_root);
    }

问题:为什么要在类的私有部分写_Inorder,在公有部分要调用Inorder,只有公有部分的才可以调用在类外面使用?那为什么不直接将_Inorder写在类公有部分:

这里是的面向对象设计中的封装性与接口设计的体现:
1.封装实现细节(隐藏私有办法)_Inorder是递归实现的内部细节,它需要接受Node* 类型的根节点参数才可以工作,如果直接暴露为公有接口,用户需要理解树的内部节点结构,甚至要处理nullptr的边界情况,这就违背了封装隐藏实现细节的原则。
_Inorder放在私有部分,可以避免用户直接调用。
2.提供了简易的公有接口。
Inorder时对外提供的“遍历接口”调用方法可简单。

案例测试:

#include"BinaryTree.h"

int main()
{
   
    BSTree<int> t;
    int a[] = {
    8,7,9,3,5,4,5,7,8,6,1,2 ,19};
    for (auto e : a)
    {
   
        t.Insert(e);
    }
    t.Inorder();
}

二叉搜索树的查找:

从根开始走,如果大于根就往右边查找,小于根就往左边查找;
最多查找高度次,如果走到空了还没有找到,那就说明这个值不存在.
如果不支持插入相等的值,找到即可返回.
如果没有去重,那么只需要找到位于中序的第一个x.

bool Find(const K& key)
{
   
    Node* cur = _root;
    while (cur)
    {
   
        if (cur->_val > key) {
    cur = cur->_left; }
        else if (cur->_val < key) {
    cur = cur->_right; }
        else {
    return true; }
    }
    return false;
}

二叉树的删除

这里就有难度的上升了,如果是叶子节点那就很好删了,删除叶子节点之后,为了防止父亲节点的叶子节点指向空位野指针,所以这里将删除的父亲节点的叶子节点置为空。
还有一种情况也是很好删除的,如果是只有一个子节点的父亲节点,删除之后让爷爷节点指向这个已删除的父亲节点的子节点。这样就完成了二叉树的连贯性。
这里再简练一点说明:“

1.要删除节点N左右孩子为空(删除叶子节点情况):把N节点的父亲节点对应孩子指针指向空,直接删除N节点;

2.1 要删除的节点N左孩子为空,右孩子不为空:把要删除节点N的父亲对应孩子指针指向N的右孩子,之直接删除N节点。
2.2 要删除的节点N右孩子为空,左孩子不为空:把要删除节点N的父亲对应孩子指针指向N的左孩子,之直接删除N节点。

要删除的N节点左右孩子都不为空:这里就需要引入替代法,形象一点理解,如果一个父亲有很多个孩子,有一天父亲要出远门,所有的孩子都送到爷爷家,爷爷照顾不过来,这样就可以让家里一个最大的孩子来照顾,这种情况是右子树。所以,找N左子树的值最大节点R(最右节点)或者N右子树的最小节点R(最左节点)替代N,因为这两个节点中任意一个,放到N的位置都满足二叉搜索树的规则。
**

这里直接看图吧!!!强烈建议看图理解!

1706.png


*
写一个大致的框架:*

bool Erase(const K& key)
{
   
    Node* cur=_root;
    while(cur)
    {
   
        if(cur->val>key){
   parent=cur;cur=cur->left;}
        else if(cur->val<key){
   parent=cur;cur=cur->right;}
        else{
   
        //删除
        //左为空
            if(cur->_left==nullptr)
            {
   }
            //右为空
            else if(cur->_right==nullptr)
            {
   }
            else
            {
   //左右都不为空
            }    
        }
    }
    return false;
}

删除的时候要分为三种情况。

  1. 左为空

1438.png

//左为空
if(cur->_left == nullptr)
{
   
                if (cur == _root) {
    _root = cur->_right; }

                else
                {
   
                    if (parent->_left == cur)//左为空,又是父亲的左
                    {
   
                        parent->_left = cur->_right;
                    }
                    else//左为空,但是又是父亲的右
                    {
   
                        parent->_right = cur->_right;
                    }
                }
                delete cur;
}
  1. 右为空

1439.png

//右为空
else if (cur->_right == nullptr)
{
   
                if (cur == _root) {
    _root = cur->_left; }

                else
                {
   
                    if (parent->_left == cur)
                    {
   
                        parent->_left = cur->_left;
                    }
                    else {
    parent->_right = cur->_left; }
                }
                delete cur;//删除掉cur元素
}

注意!!!还有一种情况:假如是删除根节点:此时也可以分别插入到上面的情况:
根节点的左边为空,右边不为空,也即是cur==_root;则将cur的右赋值给_root;_root=cur->_right;
根节点的右边为空,左边不为空,也即是cur==_root,则将cur的左赋值给_root;_root=cur->_left;

  1. 左右都不为空

    左右都不为空,此时需要替代,用右子树的最小节点或者是左子树的最大节点替代都不违反二叉搜索树的特性即可

else
{
   //左右都不为空,此时需要替代,用右子树的最左节点或者是左子树的最右节点替代都不违反二叉搜索树的特性即可
                Node* replaceParent = cur;
                Node* replace = cur->_right;
                while (replace->_left)
                {
   
                    replaceParent = replace;
                    replace = replace->_left;
                }
                cur->_val=replace->_val;//不可以交换位置,就是将replace的值赋值给cur,此时完成了交换
                if (replaceParent->_left == replace)
                    replaceParent->_left = replace->_right;
                else
                    replaceParent->_right = replace->_right;
                delete replace;
}

image.png

image.png

搜索二叉树的修改:

普通搜素二叉树不可以被修改。否则会破坏性质。

二叉搜索树源码:

#pragma once
#include<iostream>
using namespace std;

namespace Key
{
   
    template <class K>
    struct MyBSTNode
    {
   
        K _key;
        MyBSTNode<K>* _left;
        MyBSTNode<K>* _right;

        MyBSTNode(const K& key)
            :_key(key)
            ,_left(nullptr)
            ,_right(nullptr)
        {
    }

    };

    template<class K>
    class MyBSTree
    {
   
        using Node = MyBSTNode<K>;
    public:
        bool Insert(const K& key)
        {
   
            if (_root == nullptr) {
    _root = new Node(key); return true; }
            Node* cur = _root;
            Node* parent = nullptr;
            while (cur)
            {
   
                if (cur->_key < key) {
    parent = cur; cur = cur->_right; }
                else if (cur->_key > key) {
    parent = cur; cur = cur->_left; }
                else {
    return false; }
            }
            cur = new Node(key);
            if (parent->_key < key) {
   parent->_right=cur; }
            else {
    parent->_left = cur; }

            return true;
        }

        bool find(const K& key)
        {
   
            Node* cur = _root;
            while(cur)
            {
   
                if (cur->_key > key) {
    cur = cur->_left; }
                else if(cur->_key<key){
    cur = cur->_right; }
                else {
    return true; }
            }
            return false;
        }

        bool Erase(const K& key)
        {
   
            Node* cur = _root;
            Node* parent = nullptr;
            while (cur)
            {
   
                        if (cur->_key > key) {
    parent = cur; cur = cur->_left; }
                        else if (cur->_key < key) {
    parent = cur; cur = cur->_right; }
                        else 
                        {
       
                            if (cur->_left == nullptr)//左为空
                            {
   
                                if (cur == _root) {
    _root = cur->_right; }
                                else
                                {
   
                                    if (parent->_left == cur) {
    parent->_left = cur->_right; }
                                    else {
    parent->_right = cur->_right; }
                                }
                                delete cur;
                            }
                            else if (cur->_right == nullptr)//右为空
                            {
   
                                if (cur == _root) {
    _root = cur->_left; }
                                else
                                {
   
                                    if (parent->_left == cur) {
    parent->_left = cur->_left; }
                                    else {
    parent->_right = cur->_left; }
                                }
                                delete cur;
                            }
                            else
                        {
   
                            //左右都不为空
                            Node* replaceParent = cur;

                            //替代节点:左子树的最右节点
                            Node* replace = cur->_left;
                            while (replace->_right)
                            {
   
                                            replaceParent = replace;
                                            replace = replace->_right;
                            }
                            cur->_key = replace->_key;
                            if (replaceParent->_left == replace) {
    replaceParent->_left = replace->_left; }
                            else {
    replaceParent->_right = replace->_left; }

                            //替代节点:右子树的最左节点
                            /*Node* replace = cur->_right;
                            while (replace->_left)
                            {
                                            replaceParent = replace;
                                            replace = replace->_left;
                            }
                            cur->_key = replace->_key;
                            if(replaceParent->_left==replace){replaceParent->_left = replace->_right; }
                            else { replaceParent->_right = replace->_right; }*/

                            delete replace;
                        }
                            return true;
                    }
            }
            return false;
        }

        void Inorder()
        {
   
            _Inorder(_root);
            cout << endl;
        }
    private:
        void _Inorder(Node* root)
        {
   
            if (root == nullptr)
            {
   
                return;
            }
            _Inorder(root->_left);
            cout << root->_key << " ";
            _Inorder(root->_right);
        }

    private:
        Node* _root = nullptr;
    };
}

测试:

#define _CRT_SECURE_NO_WARNINGS 1
#include"BinaryTree.h"

int main()
{
   
    Key::MyBSTree<int>t;
    int a[] = {
    8,7,9,3,5,4,5,7,8,6,1,2 ,19,99 };
    for (auto e : a)
    {
   
        t.Insert(e);
    }
    t.Inorder();

    t.Erase(19);
    t.Inorder();
}

二叉树搜索树的应用:

小区停车,会检查车牌号,在本小区里面的车,会登记车牌号录入后台系统,非本小区的车想要进去,就会显示“非本小区车辆”
检查一篇文章中的英文字母有没有拼写错误,将词库中所有单词都放入二叉搜索树,读取文章的单词,查找是否在二叉搜索树中,不在波浪线中则标红提示。

key/value搜索场景:

每一个关键码key都有一个对应的值value,value可以是任意类型的对象,树的节点中除了存储key还要存储对应的value,增删查还是以Key为关键字走二叉搜索树的规则进行比较,可以快速的查找到key对应的value,key/value的搜索树支持修改,但是不支持修改key,修改key就会破坏搜索树的结构,可以修改value.

场景1:简单中英互译字典:树的结构中(节点)存储key(英文)和value(中文),搜索时输入英文,则同时会查找到中文。

场景2:商场车库:入库时扫描车牌,记录车牌和入场时间,出口离开,扫描车牌,查找 入场时间,用当前时间—入场时间计算出停车时间长,计费让车离开。

KV搜索树的析构:

private:

    void Destroy(Node* root)
    {
   
        if (root == nullptr)
            return;
        Destroy(root->_left);
        Destroy(root->_right);
        delete root;
    }
public:
        ~MyBSTree()
        {
   
            Destroy(_root);
            _root=nullptr;
        }

KV搜索树的拷贝:(用前序遍历拷贝这棵树的节点)

private:
        Node* Copy(Node* root)
        {
   
            if (root == nullptr)
                return nullptr;

            Node* newRoot = new Node(root->_key, root->_value);
            newRoot->_left = Copy(root->_left);
            newRoot->_right = Copy(root->_right);

            return newRoot;
        }
public:
    MyBSTree()=default;
    MyBSTree(const MyBSTree& t)
    {
   
        _root = Copy(t._root);
    }

这里会有如下的报错,加上MyBSTree()=default;强制生成构造即可。
image.png

赋值:

public:
    MyBSTree& operator=(MyBSTree tmp)
    {
   
        swap(_root, tmp._root);
        return *this;
    }

KV二叉搜索树源码实现:

KV二叉搜索树源码实现:

#include<iostream>
using namespace std;

namespace Key_Value
{
   
    template <class K,class V>
    struct MyBSTNode
    {
   
        K _key;
        V _value;
        MyBSTNode<K,V>* _left;
        MyBSTNode<K,V>* _right;

        MyBSTNode(const K& key,const V& value)
            :_key(key)
            ,_value(value)
            ,_left(nullptr)
            ,_right(nullptr)
        {
    }

    };

    template<class K,class V>
    class MyBSTree
    {
   
        using Node = MyBSTNode<K,V>;
    public:

        MyBSTree() = default;
        MyBSTree(const MyBSTree& t)
        {
   
            _root = Copy(t._root);
        }

        ~MyBSTree()
        {
   
            Destroy(_root);
            _root = nullptr;
        }

        MyBSTree& operator=(MyBSTree tmp)
        {
   
            swap(_root, tmp._root);
            return *this;
        }
        bool Insert(const K& key,const V& value)
        {
   
            if (_root == nullptr) {
    _root = new Node(key,value); return true; }
            Node* cur = _root;
            Node* parent = nullptr;
            while (cur)
            {
   
                if (cur->_key < key) {
    parent = cur; cur = cur->_right; }
                else if (cur->_key > key) {
    parent = cur; cur = cur->_left; }
                else {
    return false; }
            }
            cur = new Node(key,value);
            if (parent->_key < key) {
   parent->_right=cur; }
            else {
    parent->_left = cur; }

            return true;
        }

        Node* find(const K& key)
        {
   
            Node* cur = _root;
            while (cur)
            {
   
                if (cur->_key > key) {
    cur = cur->_left; }
                else if(cur->_key<key){
    cur = cur->_right; }
                else {
    return cur; }

            }

            return nullptr;
        }

        bool Erase(const K& key)
        {
   
            Node* cur = _root;
            Node* parent = nullptr;
            while (cur)
            {
   
                        if (cur->_key > key) {
    parent = cur; cur = cur->_left; }
                        else if (cur->_key < key) {
    parent = cur; cur = cur->_right; }
                        else 
                        {
       
                            if (cur->_left == nullptr)//左为空
                            {
   
                                if (cur == _root) {
    _root = cur->_right; }
                                else
                                {
   
                                    if (parent->_left == cur) {
    parent->_left = cur->_right; }
                                    else {
    parent->_right = cur->_right; }
                                }
                                delete cur;
                            }
                            else if (cur->_right == nullptr)//右为空
                            {
   
                                if (cur == _root) {
    _root = cur->_left; }
                                else
                                {
   
                                    if (parent->_left == cur) {
    parent->_left = cur->_left; }
                                    else {
    parent->_right = cur->_left; }
                                }
                                delete cur;
                            }
                            else
                            {
   
                                //左右都不为空
                                Node* replaceParent = cur;

                                //替代节点:左子树的最右节点
                                /*Node* replace = cur->_left;
                                while (replace->_right)
                                {
                                    replaceParent = replace;
                                    replace = replace->_right;
                                }
                                cur->_key = replace->_key;
                                if (replaceParent->_left == replace) { replaceParent->_left = replace->_left; }
                                else { replaceParent->_right = replace->_left; }*/

                                //替代节点:右子树的最左节点
                                Node* replace = cur->_right;
                                while (replace->_left)
                                {
   
                                    replaceParent = replace;
                                    replace = replace->_left;
                                }
                                cur->_key = replace->_key;
                                if(replaceParent->_left==replace){
   replaceParent->_left = replace->_right; }
                                else {
    replaceParent->_right = replace->_right; }

                                delete replace;
                            }
                            return true;
                        }
            }
            return false;
        }

        void Inorder()
        {
   
            _Inorder(_root);
            cout << endl;
        }
    private:

        void Destroy(Node* root)
        {
   
            if (root == nullptr)
                return;
            Destroy(root->_left);
            Destroy(root->_right);
            delete root;
        }

        Node* Copy(Node* root)
        {
   
            if (root == nullptr)
                return nullptr;

            Node* newRoot = new Node(root->_key, root->_value);
            newRoot->_left = Copy(root->_left);
            newRoot->_right = Copy(root->_right);

            return newRoot;
        }

        void _Inorder(Node* root)
        {
   
            if (root == nullptr)
            {
   
                return;
            }
            _Inorder(root->_left);
            cout << root->_key << " :" << root->_value << endl;
            _Inorder(root->_right);
        }

    private:
        Node* _root = nullptr;
    };
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"BinaryTree.h"

//int main()
//{
   
//    Key::MyBSTree<int>t;
//    int a[] = { 8,7,9,3,5,4,5,7,8,6,1,2 ,19,99 };
//    for (auto e : a)
//    {
   
//        t.Insert(e);
//    }
//    t.Inorder();
//
//    t.Erase(4);
//    t.Inorder();
//}

int main()
{
   

    string arr[] = {
   "冬","春","冬", "春","夏" };
    Key_Value::MyBSTree<string, int>countTree;

    for (const auto& str : arr)
    {
   
        auto ret = countTree.find(str);
        if (ret == nullptr)
        {
   
            countTree.Insert(str, 1);
        }
        else
        {
   
            //修改value
            ret->_value++;
        }
    }
    countTree.Inorder();
    return 0;
}
相关文章
|
数据采集 机器学习/深度学习 算法框架/工具
利用Python实现基于图像识别的自动化数据采集系统
本文介绍了如何利用Python编程语言结合图像识别技术,构建一个自动化的数据采集系统。通过分析图像内容,实现对特定信息的提取和识别,并将其转化为结构化数据,从而实现高效、准确地采集需要的信息。本文将详细讨论系统的设计思路、技术实现以及应用场景。
|
网络协议 网络架构
数据从发出到接收的细节介绍{封装与解封装}
本文将介绍了详细的封装在每一层的具体的操作,可以让大家学习到数据从发出到收到的具体过程。
|
4月前
|
人工智能 程序员 开发者
2025年程序员如何挣钱?卓伊凡的七条职业发展路径分析-优雅草卓伊凡
2025年程序员如何挣钱?卓伊凡的七条职业发展路径分析-优雅草卓伊凡
420 6
|
8月前
|
智能硬件
《Code to All-Stack|Bolt.diy 一步搞定创意建站》获奖名单公布!
《Code to All-Stack|Bolt.diy 一步搞定创意建站》获奖名单公布!
170 0
|
6月前
|
安全 数据库 C#
阿里云最新域名注册和续费、云虚拟主机、企业邮箱收费价格表参考
域名,云虚拟主机,企业邮箱是阿里云旗下的基础产品,2025年截止目前阿里云平台注册.com域名的收费标准是85元,新用户首次注册可享受一定的优惠。本文为大家介绍2025年阿里云在域名注册与续费、云虚拟主机、以及企业邮箱方面的最新收费标准与优惠政策,帮助用户更好的了解自己所需产品的收费标准,以供参考。
|
6月前
|
人工智能 运维 安全
智能体安全与可信AI:防护机制与伦理考量
作为一名长期专注于人工智能安全领域的技术博主"摘星",我深刻认识到随着智能体(AI Agent)技术的快速发展和广泛应用,其安全性和可信度已成为当前AI领域最为关键的挑战之一。在过去几年的研究和实践中,我见证了从简单的规则基础智能体到复杂的大语言模型驱动智能体的演进历程,同时也观察到了伴随而来的各种安全威胁和伦理问题。智能体系统不仅面临着传统网络安全中的攻击威胁,还要应对AI特有的对抗攻击、数据投毒、模型窃取等新型安全挑战。更为复杂的是,智能体的自主决策能力使其在执行任务时可能产生意想不到的行为,这不仅涉及技术层面的安全防护,更触及了AI伦理、责任归属、隐私保护等深层次问题。本文将从智能体安全
566 0
|
安全 Cloud Native Shell
云上攻防:云原生篇&Docker容器逃逸
本文介绍了Docker的基本概念及其对渗透测试的影响,重点讲解了容器逃逸的方法。Docker是一种轻量级的容器技术,与虚拟机相比,具有更高的便携性和资源利用率。然而,这也带来了安全风险,特别是容器逃逸问题。文章详细描述了三种常见的容器逃逸方法:不安全的配置、相关程序漏洞和内核漏洞,并提供了具体的检测和利用方法。此外,还介绍了几种特定的漏洞(如CVE-2019-5736和CVE-2020-15257)及其复现步骤,帮助读者更好地理解和应对这些安全威胁。
1060 3
云上攻防:云原生篇&Docker容器逃逸
|
存储 缓存 Linux
【实战指南】嵌入式RPC框架设计实践:六大核心类构建高效RPC框架
在先前的文章基础上,本文讨论如何通过分层封装提升一个针对嵌入式Linux的RPC框架的易用性。设计包括自动服务注册、高性能通信、泛型序列化和简洁API。框架分为6个关键类:BindingHub、SharedRingBuffer、Parcel、Binder、IBinder和BindInterface。BindingHub负责服务注册,SharedRingBuffer实现高效数据传输,Parcel处理序列化,而Binder和IBinder分别用于服务端和客户端交互。BindInterface提供简单的初始化接口,简化应用集成。测试案例展示了客户端和服务端的交互,验证了RPC功能的有效性。
799 83
|
算法
数据结构和算法学习记录——二叉搜索树的插入操作、删除操作
数据结构和算法学习记录——二叉搜索树的插入操作、删除操作
305 0
|
测试技术 C语言
单链表之无头链表(C语言版)
本文详细介绍了使用C语言实现无头单链表的方法,包括节点和链表结构的定义、链表的创建与销毁、节点的插入与删除,以及链表的打印等功能。文章通过具体的代码示例,展示了如何在无头链表中进行头插法、尾插法、自定义位置插入和删除,以及如何清空和销毁链表。
354 0
单链表之无头链表(C语言版)

热门文章

最新文章