今天是释然发题解的第四天,以后每一天都会和大家分享学习路上的心得,希望和大家一起进步,一起享受coding的乐趣。
本文约2500字,预计阅读10分钟
昨天我们学习了结构,忘记的小伙伴们可以看一下哦:
今天我们来聊一聊链表,但是链表的知识必须预先掌握
指针 和 结构 的相关知识。明天和大家分享计算机等级考试的相关内容:
链表的定义:
首先我们要知道链表是用来干嘛的,我们引用百度百科中的定义:
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
总结一下意思就是:
链表是一种常见的重要的数据结构,它是由多个节点构成,每个节点是由数据域和指针域组成,数据域是存放数据的,而指针域存放下一结点的地址
它是动态地进行存储分配的一种结构因此链表它在内存中的地址不是连续的
一个特殊的链表:带表头结点的单链表
表头结点位于表的最前端,本身不带数据,仅标志表头
设置表头结点的目的是统一空表与非空表的操作,简化链表操作的实现。
其数据域一般无意义,但有些情况下也可存放链表的长度
创建一个链表
如果我们要创建一个结点怎么办呢?用一个函数就可以创建成千上万个结点
创建一个结点的一般形式为:
struct Node//这个函数就可以创建多个结点
{
int data;//数据域
struct node *next;//指针域
};
因为链表的特殊性,我们需要动态地分配内存
#include<malloc.h>
//头文件需要加入这个,如果使用malloc函数的话
head=(struct node *)malloc(sizeof(struct node));
//动态地分配内存函数,每创建一个结点都需要这么做
#include <new>
//使用new
head=new Node;
//这样写也可以,至于 new 和 malloc的区别有这样的一篇文章
创建一个链表,使用new
Node *Create(int n)
{ int m=0;
Node*head,*p1,*p2;
p1=p2=new Node;
cin>>p1->data;
head=NULL;
while(p1->data!=0)
{
if(m==0)
{
head=p1;
}
else
p2->next=p1;
p2=p1;
if( m<n-1)
p1=new Node;
else
break;
cin>>p1->data;
m++;
}
p2->next=NULL;
return head;
}
也可以使用malloc函数创建
void *Create(int *data,int n)
{
head=(struct Node *)malloc(sizeof(struct Node));
head->data=n;//存放链表的长度
head->next=head;
Current=head;
int i = 0;
for(i = 0;i<n;i++)
{
cin>>Current->data;
if(i< n-1)
{
Current->next =(struct node *)malloc(sizeof(struct node));
Current= Current->next;
}
}
Current->next= NULL;
}
插入元素
void insert(Node*head,int p,int x)
{ //p是插入的位置,x是插入的数据域
Node*tmp=head;//循环是为了防止插入位置超出了链表长度
for(int i=0;i<p;i++)
{
if(tmp==NULL)
return;
if(i<p-1)
tmp=tmp->next;
}
Node*tmp2=new Node;
tmp2->data=x;
tmp2->next=tmp->next;
tmp->next=tmp2;
}
删除元素
//head链表头指针,p被删除元素位置
//如果删除失败返回-1
int delete(Node*head,int p)
{
Node*tmp=head;
for(int i=0;i<p;i++)
{
if(tmp==NULL)
return-1;
if(i<p-1)
tmp=tmp->next;
}
int ret=tmp->next->data;
tmp->next=tmp->next->next;
return ret;
}
遍历
int GetLength(Node *head)
{
int Length = 0;
Node *Current = (Node *)head;
while (Current)
{
Length++;
Current = Current->next;
}
return Length;
}
我也找了一个大佬写的链表,肯定比我写的要好呀,而且很全面。所以每天都要学一点呀,才能更快读地学习。手写文章的目的就是为了判断自己掌握了没有,只有手写出来的才是自己的
好了,今天的初始链表就到这里,释然也是学了好久才略微弄懂它的原理呢
释然每天发布一点自己学习的知识,希望2年后我们也能在ACM的赛场上见面,一起去追寻自己的程序猿之路吧!
后期也会和大家一起分享学习心得和学习经验呢,明天我们不见不散哦!
下期预告:
计算机等级考试C语言专题
如果大家有什么建议或者要求请后台留言,释然也想和大家一起进步呀!
联系方式:shirandexiaowo@foxmail.com