单链表删除所有值为x的元素_线性表之单链表

本文详细介绍了单链表的数据结构,包括其存储结点的构成和链表的操作,如插入、查找和删除。单链表适用于频繁的增删操作,每个结点包含数据域和指针域。带附加头结点的链表在操作上更为简便。插入操作通过在指定位置前后调整指针实现,查找操作从头结点开始遍历直到找到目标值,删除操作则需要断开指针连接并释放内存。此外,还讨论了单链表的优点和缺点,以及创建链表的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 单链表

一种以链接方式存储的线性表,适用于频繁增删操作,存储空间不定的情形。

单链表的一个存储结点包含两个域,数据域和指针域。数据域用于存储线性表的一个数据元素,指针域用于指示下一个结点开始的存储地址。

b51a6a8a592f7d0b3237826f81342528.png

链表第一个结点的地址可通过头指针找到,其他结点的地址则在前驱结点的指针域中,最后一个结点没有后继,用NULL终结。

cc697b8cc175d4d2473d1725b16783fe.png

为了操作的方便,习惯上单链表带一个头结点,也就是first指向的第一个结点不存放任何数据,从第二个结点开始存放数据。

881f993194f6a4599bc66db8bf99665f.png

由于指针域的存在,数据元素的顺序与物理存储顺序可能不一致。

e8eadd10c8133f775ad26c1e3489d2da.png

定义与封装

//结点的定义
struct LinkNode {        //链表结点类的定义int data;           //数据域
    LinkNode *link;     //链指针域

    LinkNode() { link = NULL; }     //构造函数
    LinkNode(int item, LinkNode *ptr = NULL)
    { data = item;  link = ptr; }     //构造函数
};
//链表操作封装
class List{protected:LinkNode *first;     //表头指针,头结点public:
    List() { first = new LinkNode; }  //构造函数
    List(int x) { first = new LinkNode(x); }
    ~List(){ }                  //析构函数void inputFront (int val);LinkNode *Search(int x);    //搜索含x元素LinkNode *Locate(int i);    //返回第i个元素地址bool Insert (int i, int x); //在第i元素后插入bool Remove(int i, int& x); //删除第i个元素bool IsEmpty() const         //判表空否{ return first->link == NULL ? true : false; }void show();
};

带附加头结点的插入操作

1、newnode->link = p->link; 

2、p->link = newnode;

c81239242ffbbb40fd5570b547ba6011.png

注意图中标1和2的位置与代码相结合

//将新元素 x 插入在链表中第 i 个结点之后。
bool List::Insert (int i, int x) {
    LinkNode *current = Locate(i);if (current == NULL) return false;   //无插入位置 LinkNode *newNode = new LinkNode(x); //创建新结点    //图中标识的1处,在不破坏原链表的情况下让新结点先链入
    newNode->link = current->link;       //链入    //图中标识的2处,接到新结点
    current->link = newNode;  
          return true;                
}

带附加头结点的查找操作

查找过程就是从第一个结点开始不断沿着link域寻到和所需值相同的结点

//在表中搜索含数据x的结点, 搜索成功时函数返//该结点地址; 否则返回NULL。
LinkNode *List::Search(int x) {
     LinkNode *current = first->link;while( current != NULL && current->data != x )      
        current = current->link;    //沿着链找含有x的结点
return current;
}

带附加头结点的删除操作

1、q = p->link;

2、p->link = q->link;

3、delete q; 

7ea861224de9bb6c887fb1ec680e1eae.png

//删除链表第i个元素, 通过引用参数x返回元素值
bool List::Remove (int i, int& x ) {//图中指针p
    LinkNode *c
urrent = Locate(i-1);if(current == NULL || current->link == NULL)   return false;     //删除不成功      //图中指针q
    LinkNode *del = current->link; 
    //图中操作2,p的link指向指针q的link指向的域,越过q
    current->link = del->link;

    x = del->data;    //脱节的q可以直接删除   delete del; return true;
}

附加头结点的单链表创建

一般单链表的创建可采用前插法或者尾插法,

前插法就是每来一个新的结点,就把这个结点插在头结点的后面。

尾插法就是每来一个新的结点就把这个结点插在链表最后一个结点的后面,相比前插法需要设置一个尾指针。

实现插入过程和链表的插入操作几乎无区别。

void List::inputFront (int val) {
    LinkNode *newNode = new LinkNode;if(newNode==NULL) return;
    newNode = new LinkNode(val);newNode->link = first->link;      //插在表前端
    first->link = newNode;

}

优点:

长度很容易方便扩充。

缺点:

存储空间上多了指针域,存储空间代价比顺序表大。

至于带附加头节点和不带附加头节点的好处,看过书的同学都知道,前者的增删操作更简练

代码https://github.com/xiaoYaChh/datastructure.git

参考资料:数据结构第二版,殷人昆,清华大学出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值