链表与数组的区别--以及单链表C++语言实现

C++实现单链表

链表和数组的区别

数组的特点:

  1. 在内存中连续存放,可以通过下标迅速访问数组的任何元素,数组的插入和删除数据效率低,因为插入位置后的元素都要向后移动,删除位置后的元素都要向前移动。
  2. 随机读取效率高,因为数组是连续的,知道每一个数据的内存地址,可以直接找到该地址的数据。
  3. 数组需要预留空间,在使用前要先申请占内存的大小,可能会浪费空间,并且数组不利于扩展,数组所定义的空间不够时需要重新定义数组

链表的特点:

  1. 内存中非顺序存储,而是通过元素中的指针链接在一起。
  2. 访问元素需要从第一个元素开始–顺序查找
  3. 增加和删除相对简单,只需要修改指针不需要移动元素
  4. 链表不需要指定大小,扩展比较方便,增删比较方便

链表和数组的优缺点

数组的优点
  1. 随机访问强
  2. 查找速度快
数组的缺点
  1. 插入和删除效率低
  2. 可能浪费内存
  3. 内存空间要求高,必须要有足够连续的内存空间
  4. 数组大小固定 ,不能动态扩展
链表的优点
  1. 插入删除速度快
  2. 内存利用率高,不会浪费内存
  3. 大小没有固定、拓展很灵活
链表的缺点
  1. 不能够随机查找,查找效率低

类的声明源码

//
// Created by HANWENKE on 2022/8/20.
//
#ifndef CLION_LINKLIST_H
#define CLION_LINKLIST_H
#include <iostream>
using  namespace  std;
struct Node {
public:
    //数据域
    int data;
    //next域
    Node *next;

    Node() : data(0), next(nullptr) {}

    Node(int  x) : data(x), next(nullptr) {}

    Node(int  x, Node *next) : data(x), next(nullptr) {}
};
class LinkList {
public:
        Node *head;//链表头结点'
        LinkList(){head= nullptr;}//构造函数
        ~LinkList(){DeleteAll();}//析构函数
        void InitList();;//链表初始化
        void DeleteAll();//删除所有结点
        void HeadCreat(int n);//头插法建立单链表
        void TailCreate(int n);//尾插法建立单链表
        int Length();//获取单链表的长度
        Node *GetT(const int &x);//查找值为x的元素
        Node *GetIndex(const int  &i);//查找第i个元素
        bool Insert(const int val,int i);//在第i个位置插入val;
        bool Delete(const int &val);//删除链表中值为val的结点
        void Print();//打印链表
};
#endif //CLION_LINKLIST_H

具体实现源码

//
// Created by kexib on 2022/8/20.
//

#include "LinkList.h"
void LinkList::InitList() {
    DeleteAll();
    head= nullptr;
}
//头插法建立单链表
void LinkList::HeadCreat(int n) {
    DeleteAll();
    Node *s;
    Node *p=new Node();
   //建立一个空的头结点
    p->next=nullptr;
    int i;
    for(int i=0;i<n;i++){
        s=new Node(i+10);
        s->next=p->next;
        p->next=s;
    }
    head=p;
}
//尾插法建立单链表
void LinkList::TailCreate(int n) {
    DeleteAll();
    Node *s;
    Node *pre= nullptr;
    Node *p=new Node();
    p->next= nullptr;
    for(int i=0;i<n;i++){
        s=new Node(i+100);
        if(pre==nullptr){
            p->next=s;
            pre=s;
        }else{
            //记录上一个结点
            pre->next=s;
            pre=s;
        }
    }
    head=p;
}

void LinkList::Print() {    Node *p;
    p=head->next;
    while(p){
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
}

void LinkList::DeleteAll() {
    Node *p=head,*q;
    while(p){
        q=p->next;
        delete p;
        p=q;
    }
    head== nullptr;
}

int LinkList::Length() {
    Node *p=head->next;
    if(p== nullptr){
        return 0;
    }
    int count=0;
    while(p){
        count++;
        p=p->next;
    }
    return count;
}

Node *LinkList::GetT(const int &x) {
    Node *p=head;
    if(p== nullptr){
        return nullptr;
    }
    while(p){
        if(p->data==x){
            return p;
        }
        p=p->next;
    }
    return nullptr;
}

Node *LinkList::GetIndex(const int &i) {
    //如果访问的位置大于length-直接返回
    if(i>this->Length()){
        return nullptr;
    }
    Node *p=head->next;
    int count=0;
    while(p!= nullptr&&count!=i-1){
        count++;
        p=p->next;
    }
    return p;
}

bool LinkList::Insert(const int val, int i) {
    //如果小于0或者大于1整个长度的话,那么位置不合法
    if(i<0||i>this->Length()){
        return false;
    }
    //在尾部插入--找到最后一个结点的位置,让最后一个结点的位置指向新结点
    if(i==this->Length()){
        Node *p=head->next;
        //最后一个结点的next为空所以在这里终止条件是p->next
        while (p->next){
            p=p->next;
        }
        Node *newNode=new Node(val);
        p->next=newNode;
        return true;
    }
    //在头部插入
    if(i==0){
        //在头部插入,只需要让头节点的next指向新的结点--让新结点指向头结点的next就OK
        Node *newNode=new Node(val);
        //这里二者顺序不能够换--如果发生改变则将指向空
        newNode->next=head->next;
        head->next=newNode;
        return true;
    }
    //在某个具体的位置插入具体的值
    Node *p=head->next;
    //因为要找上这个位置的上一个结点,并且结点的个数是从0开始所以是<i-2
    for(int j=0;j<i-2;j++){
        p=p->next;
    }
    Node *newNode=new Node(val);
    newNode->next=p->next;
    p->next=newNode;
    return false;
}

bool LinkList::Delete(const int &val) {
    //首先第一步找到这个结点的值-其次要找这个结点上一个位置的结点,让上一个结点的next指向当前结点的next
    //然后delete释放当前结点
    Node *p=head->next,*q=head;
    while(p->data!=val&&p!= nullptr){
        p=p->next;
        q=q->next;
    }
    //没有找到对应的值
    if(p== nullptr){
        return false;
    }
    q->next=p->next;
    delete p;
    p= nullptr;
    return true;
}

int main(){
    LinkList L;
    L.InitList();
    //L.HeadCreat(10);
    L.TailCreate(10);
    L.Print();
    cout<<L.Length()<<endl;
    Node *temp=L.GetT(101);
    if(temp== nullptr){
        cout<<"不存在"<<endl;
    }else{
        cout<<temp->data<<endl;
    }
    temp=L.GetIndex(4);
    if(temp!= nullptr){
        cout<<temp->data<<endl;
    }
    //最后一个位置插入
    L.Insert(20,10);
    L.Insert(10,0);
    //在第3个位置插入55
    L.Insert(55,3);
    //
    L.Print();
    //删除第一个元素
    L.Delete(10);
    L.Print();
    //删除中间位置元素
    L.Delete(55);
    L.Print();
    //删除最后一个位置的元素
    L.Delete(20);
    L.Print();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HANWEN KE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值