数据结构:线性表之单链表

本文探讨了单链表与顺序表在存储结构、查找、插入和删除操作上的区别。链表由多个节点组成,每个节点包含数据和指向下一个节点的指针,而顺序表是一个结构体包含数组和变量。链表插入和删除更灵活,但查找可能需要遍历。顺序表查找可使用二分查找,但在插入和删除时需移动元素。
摘要由CSDN通过智能技术生成

在单链表中,存储结构是每一个节点的结构,每个节点是一个单独的结构.其中包含数据域(就是这个data变量,我们用它通指数据)和指针域(一个指向下一个节点的指针).

而在顺序表中,存储结构则是一个包含数组和变量的代表顺序表的结构体,也就是说顺序表只有一个结构,而单链表是许多节点的结构组成的,这是有些不一样的.

typedef struct Node{

        ElementType Data;

struct Node *Next;        //定义一个指向struct Node结构体的指针

}List;

关于顺序表和链表中查找一个元素

查找某个元素,链表和顺序表好像都一样,都要遍历,从头到尾比较,是不是这个元素.而顺序表好像可以通过算法(二分查找)让查找不用一个一个比较,而是只比较一部分.不知链表有没有这种让查找不用一个个比较的办法.

关于顺序表和链表中插入一个元素

顺序表插入一个元素需要把很多元素往后挪,而链表插入一个元素不需要,如果数据量巨大的话,节省了大量把元素往后挪的时间啊.   数据量小好像体现不出什么差别

关于顺序表和链表中删除一个元素

顺序表删除一个元素需要把很多元素往前挪,而链表删除一个元素只需要改变一下指针指向,如果数据量巨大的话,节省了大量时间啊.     数据量大就会体现差别

关于顺序表和链表在物理存储中存储

顺序表是顺序存储的,挨着盘儿地存,都存在一块儿;

而链表则是,一个结点就是一块儿,不同结点可以存储在不同的位置. 

 

问题一:链表的长度是多少?

在顺序表中,我们需要知道顺序表的长度,只需要顺序表结构体中变量的值,也就是length的值.

而在链表中,显然无法这样做,因为整个链表不是一个结构体,我们要知道链表的长度,只有用循环遍历一遍链表.

 

求表长:

int length(List  *Ptrl)

{ List *p = Ptrl;//设一个临时的指针P指向表的第一个结点

int j =0;

while(p){

p = p->Next;

j++;

return j;

}

 

问题二(查找): 第k个元素在哪里儿,是什么,返回一个指向这个元素的指针?  元素x是否在这个链表,在,请返回指向它的指针,不在,返回NULL.     

 留待思考:如何得到 元素x(x指的是值)处于链表中的第几个位置.      如果又想返回位置,又想返回指向x的指针怎么办?  返回值最多只能有一个,百度说:超过一个的有两种解决办法,第一返回指针,第二,返回结构体

 

利用FindKth()方法查找,得到一个指向第k个元素的指针.

 

1.按序号查找:    (注意是按序号查找,k并不是我们要查找的元素的值,而是我们要查找元素的序号,它在链表的第几个位置)

Luploading.4e448015.gif转存失败重新上传取消ist *FindKth( int k, List *Ptrl )//返回类型为List类型的指针,参数为K和指向第一个结点的指针

{ Luploading.4e448015.gif转存失败重新上传取消ist *p = Ptrl;

int i = 1;          //因为临时变量指向了第一个结点,所以i为1,代表第一个位置

while( p !=NULL  &&  i<k ){

p = p->next;

i++;

}

if( i == k )

return p;

else

return NULL;

}

2.按 元素的值查找:Find()方法

返回的是指向这个元素的指针(临时指针变量)

Luploading.4e448015.gif转存失败重新上传取消ist *Find(ElementType X,List *Ptrl){//需要传元素X的值X ,它所在链表的头结点指针

List *p = Ptrl;

while( p != NULL && p->Data != X)       

p = p->next;

return p;

}

疑问:如果 p->Data = X退出循环,不等于接着找不就行了吗?为什么要p !== NULL这个条件呢?

如果链表中没有这个元素,仅仅根据"p->Data != X"这个条件判断,可能会陷入死循环,因一直找不到,所以会一直找,导致退不出循环.p != NULL是让循环保证在链表内判断有没有元素X,如果出了链表范围,再找到了也是无意义的.出了链表,就会返回一个空指针.说明查找不成功.

只有指针p不等于空才有判断它的Data是不是X的意义,如果p=null了,说明已经出了链表,判断p->Data != X已无意义,直接退出循环.

只有p != NULL(说明在链表范围内)且p->Data != X(还没找到X)才有进入循环的意义.

仅仅"p->Data != X"一个条件无法让循环正常进行不陷入死循环.加入p != NULL 是让循环在链表所属范围内进行,出了链表这个范围就得退出循环,不然不是链表范围了你还在那儿瞎找?

问题三:为什么要有一个临时的指针变量指向第一个结点?不是已经有一个指针变量指向第一个结点了吗?

 

因为已有的那个指针变量指向了第一个结点,我们做查询操作,它的内容是不允许改变的,如果改变了,就破环了这个链表.

所以需要一个临时变量来辅助我们查询,为了不改变和破环这个我们要查询的链表.

看看这一步,p = p->Next; 如果不用辅助的临时变量进行操作,这就会改变指针指向的某一块的内容,从而破环整个链表,而利用这个临时变量,就可以不破环链表来操作得到我们想要的结果.

 

链表的插入:

在第i-1个结点后插入一个元素

一定要知道我们待插入的元素的前面一个是谁,才能把它插进去.可能因为需要让它前面一个元素的Next指向它.

(1)先构造一个新结点,用s指向

(2)再找到链表的第i-1个结点,用p指向

(3)然后修改指针,第i-1个结点的next要指向新结点,新结点的next要指向之前第i-1个结点的下一个结点,这样就完成了插入新结点的操作

利用两条语句,s->Next = p->Next ;  p->Next = s ;  这两条语句的顺序不能变.

如图所示:

 

插入操作实现:

List *Insert(ElementType X,int i,List *PtrL)      //在指针PtrL指向的链表中的第i个位置插入元素X
{
List *p,*s;
if( i == 1){                               
s = (List*)malloc(sizeof(List));//为新结点申请内存创建一个新结点,将新结点插在表头
s->data = X;
s->Next = PtrL;
return s;
}
p = FindKth( i-1,Ptrl);
if ( p == NULL ){
print("参数错误");
return NULL;
}else {
s = (List *)malloc(sizeof(List));
s->Data = X;
s->Next = p->Next;
P->Next = s;
return PtrL;
}
}

链表结点的删除(删除链表的第i个位置上的结点):

(1)先找到链表的第i-1个结点,用p指向;

(2)再用指针s指向要被删除的结点(p的下一个结点);

(3)然后修改指针,p->Next = s->Next;再删除s所指的结点;

(4)最后释放s所指结点的空间;(C语言就是这样,你申请了空间,不用了要释放,Java这时候估计不用自己释放)

删除操作实现:

List *Delete( int i,List *PtrL)
{ List *p,*s;
if( i == 1 ){ //若要删除的是表的第一个结点 
s = PtrL; //s指向第一个结点
if(Ptr !=NULL)                     //从链表删除
PtrL = PtrL->Next;
else return NULL;
free(s);
return PtrL;
}
p = FindKth(i-1,PtrL);              //查找第i-1个结点
if( p == NULL){
printf("第%d个结点不存在",i-1);
return NULL;
}else if ( p->Next == NULL ){
printf("第%d个结点不存在",i);
return NULL;
}else {
s = p->Next;                     //s指向第i个结点
p->Next = s->Next;               //从链表中删除
free(s); //释放被删除结点
return PtrL;
}
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值