数据结构3:链表

表的连式存储-链表

链表是线性表的一种存储形似。

1.链表的结构特点

值域 链域

值域(数据域):存储表元素值

链域(指针域):存储后继结点的存储地址(值单向链表)

2.链式存储结构图

首指针(表头指针):指向链表的第一个结点的指针变量。其值为首结点的存储地址。

表尾结点(最后一个结点)的链域值为空(NULL)**^**图中使用这个,表中使用NULL

链表就是v表头指针和一串相继链接的结点的总称

3.单向链表的结点结构的定义

值域 链域

可以用c语言的结构语言定义

typedef struct linkednode 		//结点类型
{	
    int data;			 		// 值域
    struct linkednode *next;	//链域
}snode,*ptr;					//结点类型名snode和指针类型名ptr
ptr hrad,p,q;					//定义指针类型变量
类型 struct linkednode * 与类型 ptr 等价
都是指向 snode 的指针类型

4.结点的链接操作

让前驱结点的链域指向后继结点

q->next=p;

唯有对链域的赋值操作才是结点的链接操作,其余形式的同类型指针之间的赋值操作,仅仅是改变指针的指向关系,丝毫不会改变结点的链接关系。

5.指定位置的插入

1.插在表头

将已经创建的指针p插入到现已存在的链域上,并且插入到头部

p->next=head;

head=p;//修改表头指针

2.插在表中

将已创建的指针p插入到现已存在的链域上,并且插入到表中,其中是将指针p插入到指针q后面

p->next=q->next;

q->next=p;

6.指定位置的删除

1.删除表头

q=head;

head=head->next;

free(q);

2.删除表中结点

p=q->next;

q->next=p->next;

free§;

7.链表的特点

  1. 结点地址不连续。
  2. 插入/删除不移动结点,耗时为o(1)。
  3. 用于动态管理

核心

  1. 使用指向结点(结构类型)的指针。
  2. 执行期间,调用动摇存储管理函数产生结点、回收结点。

8.向前插入法造表

链表的构造过程,其实就是反复插入的过程,从空链表开始,一个一个地想表中插入数据元素即可。

构造链表的通用算法

  1. 构造“空链表”
  2. 读入第一个元素值
  3. 当读入的元素值不是”输入结束标记“时,循环执行步骤4~7
  4. 申请一个新结点
  5. 将读入的元素存入新结点的值域
  6. 将新结点“插在”链表的表头
  7. 读入“下一个”元素值,转步骤3
  8. 构造完成,返回首指针
ptr createlindedA()
{
	ptr head,p;int x;
    head=NULL;//将表头指针置空
    scanf("%d",&x);//读入第一个元素
    while(x!=End_elm)//当读的不是结束标记是循环
    {
        p=(ptr)malloc(sizeof(snode));//申请一个存储节点
    	p->data=x;//置结点的值域
        p->next=head;//插在表头处
       	head=p;//表头指针指向新结点
        scanf("%d",&x);//读入下一个元素
    }
    return(head);//返回表头指针
}

9.向后插入法

构造链表的通用算法

  1. 构造“空链表”
  2. 读入第一个元素值
  3. 当读入的元素值不是”输入结束标记“时,循环执行步骤4~7
  4. 申请一个新结点
  5. 将读入的元素存入新结点的值域
  6. 将新结点“插在”链表的表尾
  7. 读入“下一个”元素值,转步骤3
  8. 构造完成,返回首指针
ptr createlindedA()
{
	ptr head,last,p;int x;
    head=NULL;//将表头指针置空
    scanf("%d",&x);//读入第一个元素
    while(x!=End_elm)//当读的不是结束标记是循环
    {
        p=(ptr)malloc(sizeof(snode));//申请一个存储节点
    	p->data=x;//置结点的值域
    	if (head==NULL)
    		{p->next=head;head=p;last=p;}
    	else
    		{last->next=p;p->next=NULL;laxt=p}
        scanf("%d",&x);//读入下一个元素
    }
    p=head;head=head->next;free(p);
    return(head);//返回表头指针
}

修改代码

ptr createlindedA()
{
	ptr head,last,p;int x;
    head=last=(ptr)malloc(sizeof(snode));
    last->next=NULL;
    scanf("%d",&x);//读入第一个元素
    while(x!=End_elm)//当读的不是结束标记是循环
    {
        p=(ptr)malloc(sizeof(snode));//申请一个存储节点
    	p->data=x;//置结点的值域
    	last->next=p;
    	p->next=NULL;
    	laxt=p
        scanf("%d",&x);//读入下一个元素
    }
    p=head;head=head->next;free(p);//删除辅助头结点
    return(head);//返回表头指针
}

向前向后插入法的比较:

  1. 空链表的形式不同
  2. 插入部位不同
  3. 使用工作指针的个数不同
  4. 监督元的处理不同
  5. 结点排列次序不同

10.单向简单链表的输出

void outlinkA(ptr p)//p是其实指针
{
    while(p!=NULL)
    {
        print("%5d",p->data);	//输出结点值
        p=p->next;				//滑动指针
    }
    printf("\n");
}

11.单向简单链表的查找

void outlinkA(ptr p,int x)//p是其实指针
{
    while(p!=NULL)
    {
        if(p->data==x)return p;	//找到x,返回p
        p=p->next;				//滑动指针
    }
    return NULL;				//查找不成功,返回空指针
}

12.自己的理解

在这里插入图片描述

注:

结点名:a,b,c

结点的值域:1,2,3,4

结点的链域:b,c,d,e

^表示null

讲解:

a->next的值为b结点的存储id

a->data的值为他的值域是1

f->next的值为空,是NULL。

实例一:已知b和c结点,然后删除c结点

b->next=c->next;

**意义:**根据上面的讲解,因为b的链域存的是c,要删除c我们只需要将b的链域改为c的链域值即可,也可以怎么理解,将原本放在b链域中的值改为我们想要的某个结点值。

实例二:在bc中间添加结点为p的结点

出于安全,我们应该先将p链接到c上,然后在将b连接到p上

p->next=c;
b->next=p;

当然,如果不按照我上面这个走,还是可以按照自己的方法写,这里举一个例子

b->next=p;
p->next=c;

难理解点:

b->next=c;

b->next=c->next;

上面这两个是完全不相同的概念,

第一个是把c结点作为b结点的链域,而第二个是把c结点的链域作为b结点的链域,意思是删除c结点。

发布了106 篇原创文章 · 获赞 21 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/jiangSummer/article/details/105029551