栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

《算法笔记》——链表

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

《算法笔记》——链表

链表
  • 一.链表的概念
  • 二. 使用malloc 函数或者new 运算符为链表结点分配内存空间
    • 2.1 malloc
    • 2.2 new运算符
    • 2.3 内存泄漏
  • 三.动态链表的基本操作
    • 3.1 创建链表
    • 3.2 查找元素
    • 3.3 插入元素
    • 3.4 删除元素

一.链表的概念

1.链表由若干个结点组成(每个结点代表一个元素),且结点在内存中的存储位置通常是不连续的。
2.链表的两个结点之间一般通过一个指针来从一个结点指向另一个结点,因此链表的结点一般由两部分构成,即数据域和指针域。数据域存放结点要存储的数据,指针域指向下一个结点的地址。这样就会产生从某个结点开始的,由指针连接的一条链式结构。

Struct node{
   typename date;  //数据域
   node *next;  //指针域
}

3.以链表是否存在头结点,又可以把链表分为带头结点的链表和不带头结点的链表。
(1)带头结点的链表:头结点一般称为head,其数据域data不存放任何内容,指针域next指向第一个数据域有内容的结点(第一个结点)。最后一个结点的next指针指向null,即空地址。如图所示为带头结点的链表:

(2)不带头结点的链表:即从第一个结点作为链表开始,与上图类似,只是没有head。

二. 使用malloc 函数或者new 运算符为链表结点分配内存空间 2.1 malloc
  1. malloc函数是C语言中stdlib.h头文件下用于申请动态内存的函数(C++11中可不需要头文件),其返回类型是申请的同变量类型的指针。如果申请失败则返回空指针NULL(失败一般发生在使用malloc申请较大的动态数组)。
  2. malloc()函数返回的是void*类型,所以用的时候要进行强制类型转换,基本用法如下:typename *p=(typename *)malloc(sizeof(typename))
    例子:
    int型变量:int *L=(int *)malloc(sizeof(int));
    node型结构体变量:node *p=(node *) malloc(sizeof(node))
2.2 new运算符
  1. new是C++中用来申请动态空间的运算符,其返回类型同样是申请的同变量类型的指针。如果申请失败(较大的动态数组),则会启动C++异常机制处理,而不是放回空指针NULL。
  2. 用法:typeame* p = new typename
    例子:
    (1)int型变量:int *p=new int
    (2)node型结构体变量:node *p =new node
2.3 内存泄漏
  1. 内存泄漏是指使用malloc和new开辟出来的内存空间在使用过后没有释放,导致其在程序结束之前始终占据内存空间。所以为了防止内存泄露,使用完malloc和new开辟出来的空间后必须释放。
  2. free函数
    (1)使用:free(p)
    (2)效果:释放指针变量p所指向的内存空间,将指针变量p指向空地址NULL。由此可知,free函数执行之后,指针变量p本身并没有消失,只不过让它指向了空地址NULL,但是它原指向的内存是确实被释放了的。malloc函数与free函数必须成对出现,否则容易产生内存泄漏
  3. detele运算符
    (1)使用:delete(p)
    (2)效果:new运算符与delete运算符必须成对出现,否则会容易产生内存泄漏
三.动态链表的基本操作 3.1 创建链表
#include
using namespace std;
struct node{  //链表结点
  int data;
  node* next;
};
node* create(int Array[])
{
  node *p,*pre,*head;  //pre保存当前结点的前驱结点,head为头结点
  head =new node;  //创建头结点
  head->next=NULL;  //头结点不需要数据域,指针域初始为NULL
  pre= head;  //记录pre为head
  for(int i=0;i<5;i++){
   p=new node;  //新建结点
   p->data=Array[i]; //数据域赋值
   p->next=NULL;  //新结点的指针域设为NULL
   pre->next=p; //前驱结点的指针域为当前新建结点的地址
   pre=p;  //把pre设为p,作为下个结点的前驱结点
  }
  return head; //返回头指针

}

int main()
{
    int Array[5]={5,3,6,1,2};
    node *L=create(Array); //新建链表,放回的头指针head赋给L
    L=L->next;  //从第一个结点开始有数据域
    while(L!=NULL){
        cout<data<<' ';  //输出每个结点的数据域
        L=L->next;
    }
    return 0;
}
3.2 查找元素
int search(node *head,int x){
  int count=0; //计数器
  node *p=head->next;  //从第一个结点开始
  while(p!=NULL){  //只要没有到链表末尾
    if(p->data==x)  count++;
    p=p->next;
  }
  return count;
}
3.3 插入元素

1.在第3个位置插入元素4的意思是指在插入完成之后第3个位置的元素就是4,即把原先第3个位置开始的元素让出来给需要插入的数。
2.如图所示在第3个位置插入元素4,操作顺序必须先把新结点的指针域next指向后继结点6,之后才能把元素3所在结点的指针域指向新结点的地址。

3. 代码

void insert(node *head,int pos,int x){  //将x插入以head为头结点的链表的第pos个位置上
    node *p=head;
    for(int i=0;inext;  //pos-1为了到插入位置的前一个结点
    }
    node *q=new node;
    q->data=x;
    q->next=p->next; //新结点的下一个结点指向原先插入位置的结点
    p->next=q; //前一个位置的结点指向新的结点
}
3.4 删除元素

1.思想:删除元素是指删除链表上所有值为给定的数x,如图删除元素6

2.操作(看图理解)
(1)由指针变量p枚举结点,另一个指针变量pre表示p指向结点的前驱结点。
(2)当p所指结点的数据域恰好为x时,进行下面三个操作:

  • 令pre所指结点的指针域next指向p所指结点的下一个结点。
  • 释放p所指结点的内存空间
  • 令p指向pre所指结点的下一个结点

3.代码

void del(node *head,int x){  //删除以head为头结点的链表中所有数据域为x的结点
  node *p=head->next; //p从第一个结点开始枚举
  node *pre=head;   //pre始终保存p的前驱结点指针
  while(p!=NULL){
    if(p->data==x){ //数据域为x,说明要删除该结点
        pre->next=p->next;
        delete(p);
        p=pre->next;
    }
    else{ //数据域不是x,pre和p都后移一位
        pre=p;
        p=p->next;
    }
  }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/384252.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号