简单理解C++链表结构--单链表

链表简介

链表是一种数据结构,由若干个节点串联而成,构成一条完整的链表。

可以把链表理解成为一列火车,每个节点,就是一节车厢。

车厢可以装货物(存储数据),每节车厢有一个挂钩(指针),连接下一节车厢。

火车头,就是链表的头节点。头节点没有数据(不装货物),实际第几个节点是从车厢开始算起。

链表还可以分为单链表、双链表、循环链表。本文先介绍一下单链表。

链表优点:

链表可以动态的存储数据,不需要一开始就把所有的空间创建出来,而且空间也不必连续。

而数组则必须一开始就确定数组的大小,创建出数组的完整空间,并且空间必须是连续的。

缺点:

不能根据索引查找,只能根据指针进行遍历。

链表的应用:

最典型的使用链表结构进行存储的数据,比如轨迹跟踪数据,需要记录每个时刻的位置、时间、角度、速度、里程等信息,并且,每个时刻的数据和它的前一时刻、后一时刻都是紧密相连的。

单链表结构

struct Node
{
  int data; //数据
  Node *next; //指向下一个节点的指针(存放下一个节点的地址)
};

这是链表的一个节点,火车头和所有车厢都是这样的一个节点。

头节点(火车头)不装数据,尾节点的挂钩(next指针)为NULL。

 

创建一个新节点

Node *p = new Node;

p->data 就是获取这个节点的数据,

p->next 既是这个节点的next成员变量,又是下一个节点

从一个节点跳到下一个节点

p = p->next;

判断是否到达尾节点

p->next != NULL

判断节点是否存在

p==NULL

注意:

p表示节点(整个车厢),p->next表示节点的成员变量next(挂钩),也表示下一个节点,这两个容易混淆。

在链表的尾节点p后面增加新节点n

n->next = NULL; //现在n是尾节点,next必须是NULL

p->next = n; //原来的尾节点p的后面是n

在任意节点p的后面插入新节点n

n->next = p->next; //原来p后面的节点,现在在n的后面了
p->next = n; //p的后面是n

删除任意节点p

删除节点后,要把p前面的节点和p后面的节点直接连接起来,因此要先找到p前面的节点。

//首先找到p前面的那个节点pre

while(pre->next != p)
{
  pre = pre->next;
}
//此时,pre是p前面的那个节点
pre->next = p->next; //前一个节点的next变量,装p的下一个节点,此时p节点没有用了
free(p); //释放p

示例代码

1.创建链表时,从1个节点开始,也就是头节点(火车头)。

2.所有对链表的操作(增删改查),都从头节点开始迭代。

3.链表长度是不包含头节点的,因为头节点没有实际数据。也可以把头节点看成第0个节点。

4.单链表尾节点的next指针必须是NULL。

#include <iostream>
using namespace std;

//单链表结构
struct Node
{
  int data;
  Node *next;
};

//创建单链表,初始只有1个头节点
Node* createSingleList()
{
  Node *head = new Node;//1个节点
  head->next = NULL;
  return head;
}


//在单链表尾部插入新节点
void addNode(Node* head, int data)
{
  Node *p = head;//定义指针,指向头节点
  Node *node = new Node;//新增节点

  //为新节点赋值
  node->next =NULL;//新增节点是最后一个节点
  node->data =data;
  //找到原链表的最后一个节点
  while(p->next != NULL)
  {
    p = p->next;
  }
  //p是原链表的最后一个节点,现在它后面是新增节点
  p->next = node;
}


//输出链表,head是头节点
void printList(Node* head)
{
  if(head==NULL) return;
  Node *p = head;//定义指针,指向头节点
  while(p->next!=NULL)
  {
    p=p->next;//指针向后递进,不打印头节点
    cout << p->data << " "; //输出数据
  }
  cout << endl;
}


//计算单链表长度,不含头节点
int lengthList(Node* head)
{
  Node *p = head;//定义指针,指向头节点
  int len = 0;
  while(p->next != NULL)
  {
    len++;
    p = p->next;
  }
  return len;
}


//取出单链表第i个节点(不算头节点)
Node* getNode(Node* head, int i)
{
  if(head == NULL) return NULL;
  int k = 0;
  Node *p = head;//定义指针,指向头节点
  while( (p->next!=NULL) && (k<i) )
  {
    p=p->next;
    k++;//此时,k和第i个节点对应
  }
  if((k==i) && (k!=0))
    return p;
  else
  {
    cout << "node is not exist";
    return NULL;
  }
}


//在第i个节点后面插入新节点
void insertNode(Node *head, int i, int data)
{
  int k = 0;
  Node* p = head;//定义指针,指向头节点
  while( (p->next!=NULL) && (k<i) ) //找到第i个节点
  {
    p = p->next;
    k++;
  }
  //此时,k=i,p是第i个节点
  if(p==NULL)
    cout << "node is not exist" << endl;
  else
  {
    Node *s = new Node;//新增节点
    s->data = data;    //赋值
    s->next = p->next; //新节点的后面就是原来p节点的下一个节点
    p->next = s;       //现在p节点的后面就是新节点s
  }
}


//在节点p后面插入新节点
void insertNode(Node *p, int data)
{
  Node* s = new Node;//创建新节点
  s->data = data;
  s->next = p->next;//新节点的下一个就是原来p节点的下一个节点
  p->next = s;//p节点的下一个是新节点
}



//删除第i个节点
void deleteNode(Node* head, int i)
{
  int k = 0;
  Node *pre = head;//定义指针,表示要删除节点的前一个节点,初始时指向头节点
  //找到这个节点前面的节点
  while( (pre->next!=NULL) && (k<i-1) )
  {
    pre = pre->next;
    k++;//此时,k和第i-1个节点对应
  }
  //此时,pre是第i-1个节点
  if(pre == NULL)
    cout << "node is not exist";
  else
  {
    Node *t;//临时节点,为了把要删除的节点内存释放
    t = pre->next;
    pre->next = pre->next->next;//pre->next里面装的是下一个的下一个节点地址
    free(t);//释放内存
  }
}


//删除指定节点
void deleteNode(Node *head, Node *p)
{
  Node *pre = head;//要删除的节点前一个节点
  
  while(pre->next!=p)
  {
    pre = pre->next;
  }
  //此时,pre是p的前一个
  if(pre == NULL)
  {
    cout << "node is not exist";
  }
  else
  {
    pre->next = p->next; //pre->next里面装的是p的下一个节点
    free(p); //释放p节点内存
  }
}



int main()
{
  //创建单链表,打印链表,链表长度,取出指定节点
  Node *head = createSingleList();//创建链表
  addNode(head,1); //添加节点
  addNode(head,2);
  addNode(head,3);
  addNode(head,4);
  addNode(head,5);
  printList(head); //结果:1 2 3 4 5
  cout << "单链表长度为:" << lengthList(head) << endl; //结果:单链表长度为:5
  Node *p = getNode(head, 4);//取出第4个节点(不算头节点)
  cout << "node 4 is:" << p->data << endl; //结果:node 4 is: 4


  //插入节点
  insertNode(p,88);//在第4个节点后面插入88
  insertNode(head, 0, 10);//在第0个节点后插入10
  printList(head);//结果:10 1 2 3 4 88 5
  cout << "单链表长度为:" << lengthList(head) << endl;//结果:单链表长度为:7


  //删除节点
  p = getNode(head, 1);//取出第1个节点(就是10)
  deleteNode(head,p);//删除指定节点
  printList(head);//结果:1 2 3 4 88 5
  deleteNode(head,5);//删除第5个节点(就是新增的88)
  printList(head);//结果:1 2 3 4 5
  deleteNode(head,5);//删除第5个节点(删除最后1个)
  printList(head);//结果:1 2 3 4

  return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

胡十三刀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值