[数据结构]线性表的链式存储- 链式存储 ,单链表

链式存储

在这里插入图片描述
最后一句表明,在这里插入图片描述k2是k1的后继结点,k3是k2的后继结点,k4是k3的后继结点,k5是k4的后继结点,k5是空的表

单链表

在这里插入图片描述
在这里插入图片描述

typedef int datatype;//简化算法,数据类型用整形表示
typedef struct link_node{
datatype info;//整型数据域
struct link_node *next;//指针域,指向本结点类型指针
}node;//取名node
typedef node *linklist;//指向结构体类型的指针取名linklist

建立一个空的单链表

赋值

node *init()
{
	return NULL;
}

int main()
{
	linklist  head;
	head=init();
}

传递指针地址

void init(linklist *p)//*p指向linklist这种类型的指针
{
	*p=NULL;//将链表指针赋值为空
}

int main()
{
	linklist head;
	init(&head);
}

输出单链表中各个结点的值

void display(node *head)//也可以是linklist  head
{
	node *p;
	p=head;//初始值指向单链表第一个结点
	if(!p) printf("/n单链表是空的!")else
	{
		printf("\n单链表各个结点值为:")
		while(p)
		{
		printf("%5d",p->info);
		p=p->next;//p赋值为p的next
		}
	}
	
}

在这里插入图片描述

  • 时间复杂度O(n)

在单链表中查找第i个结点

node *find(node *head,int i)
{
	int j=1;
	node *p=head;
	if(i<1) return NULL;
	while (p&&i!=j){
		p=p->next;
		j++;
	}
	return p;
}

若i不存在,返回的是空值

单链表插入

最前面插入值为x的新结点

  • 申请一个结点的空间,让指针指向他
    p=(linklist)malloc(sizeof(node));
  • p->info=x
  • p->next=headp->next暂时为head
  • head=phead重新指向这个链表
    在这里插入图片描述

某一个结点后面插入新结点

  • 申请一个结点的空间,让指针指向他
    p=(linklist)malloc(sizeof(node));
  • p->info=x
  • p->next=q->next
  • q->next=p
    在这里插入图片描述

算法:在单链表第i个结点后插入一个值为x的新结点

linklist insert(node *head,datatype x,int i)
{
	node *p,*q;
	q=find(head,i);
	if(!q&&i!=0)//找到的位置不存在或者i不合法
		printf("找不到%d个结点,不能插入%d",i,x);
	else{
	p=(linklist)malloc(sizeof(node));
	p->info=x
	}
	if(i==0){
	p->next=head;
	head=p
	}
	else{
	p->next=q->next;
	q->next=p;
}
return head;
}

头插法建立单链表

建立单链表

linklist creatbystack()
{  linklist  head,s;
    datatype x;
    head=NULL;
    printf("请输入若干整数序列:\n");
    scanf("%d",&x);
    while (x!=0)		/*以0结束输入*/
    {   s=(linklist)malloc(sizeof(node));  /*生成待插入结点*/
        s->info=x;
        s->next=head;			/*将新结点插入到链表最前面*/
        head=s;
        scanf("%d",&x);
    }
    return head;				/*返回建立的单链表*/
}

输出单链表

void print(linklist head)
{   linklist p;
    int i=0;
    p=head;
    printf("List is:\n");
    while(p)
    {
        printf("%5d",p->info);
        p=p->next;
         i++;
		 if (i%10==0) printf("\n");
    }
    printf("\n");
}

在这里插入图片描述

在尾部建立单链表

关键一步设置一个链尾指针r,每次将新的结点链在r的后面,使其成为新的表尾结点

linklist creatbyqueue()
{
    linklist head,r,s;//node *head,*s,*r;
    datatype x;
    head=NULL;r=NULL;//表首和表尾指针为空
    scanf("%d",&x);
    while (x!=0)
    {
         s=(linklist)malloc(sizeof(node));
         s->info=x;
       if(head==NULL) head=s//原链表为空,head指向链表第一个结点
       else r->next=s;//将s指向的结点加到r指向结点的后面
         r=s;
         scanf("%d",&x);
   }
   if(r!=NULL)
    	r->next=NULL;
    return head;
}

单链表删除

删除单链表最前面的结点

  • p=head保留删除的结点
    在这里插入图片描述

  • head=p->nexthead指向链表的第二个结点
    在这里插入图片描述

  • 释放删除结点的空间
    在这里插入图片描述

删除链表非首结点

  • 找到被删除结点的前驱结点
    在这里插入图片描述
  • pre->next=p->next删除p指示结点
    在这里插入图片描述
  • 释放被删除结点空间 free(p)
    在这里插入图片描述

算法:在单链表中删除一个值为x的结点

linklist dele(node *head,datatype x)
{
node *pre=NULL,*p;//不仅要知道p的位置,还要知道p前面的位置
if(!head){
printf("单链表是空的");
return head;
}
p=head;
while(p&&p->info!=x)//p不为空且查找的值不是x
//&&条件不能颠倒,否则视为程序非法访问内存
{
	pre=p;//pre指向p
	p=p->next//p往下走
}
if(p!=NULL)
{
if(!pre)
	head=head->next//head指向下一个结点
}else{
	pre->next=p->next;
}
free(p);
}

若链表有多个x结点,只能删除第一个结点

链式存储结构优缺点

在这里插入图片描述

课后答疑

  • 对下面代码的了解
typedef int datatype;//简化算法,数据类型用整形表示
typedef struct link_node{
datatype info;//整型数据域
struct link_node *next;//指针域,指向本结点类型指针
}node;//取名node
typedef node *linklist;//指向结构体类型的指针取名linklist

node=link_node
node*=linklist=link_node*指向结构体的指针类型

  • 建立空链表两种代码的理解
    在这里插入图片描述
    node*表示要返回node*定义的指针,那么应该在main函数里面有个专门的变量去接收返回值。所以在函数里面不需要return返回任何值!
    在这里插入图片描述
    这里void表示没有返回值,也就是说函数里面需要返回值,那么我们想要直接更改函数里的值,即main函数会跟着形参改变,我们就该传一个地址(地址传递)。这个时候就该返回return head等等了

  • p=p->next的理解
    假设前两个单元为k1,k2,让p指向k1,那么p->next是在k1中,里面保留了k2的地址

  • 由上可知,链表最后一个值一定要赋值为空

  • 删除链首结点 对head=head->next理解
    在没有头结点的情况下,head就是k1,head->next就是k1->next,即保留k2结点

  • 头插法对链表就地倒置特别注意:前面head=NULL
    为什么呢?因为在头插法中,最先进来的最后输出,当head赋值为空时,第一个进来的s 要s->next=head,即s的next指针域为空。那么当链表输出中,只有遇到空值,链表才结束。

  • 链表结束后,head,linklist定义的pre,p等等都会被自动释放掉,因为这属于动态分配内存,pre,p,head类似局部变量

  • 但是由malloc函数分配的内存,就像k1,k2,k3等,需要free来释放

  • 链表删除,插入,都不改变其他结点的位置,则其时间复杂度和空间复杂度为O(1)

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值