线性表的链式存储结构之单链表

我们上一篇博客说的线性表的顺序存储结构结构它是有缺点的,最大的 缺点就是插入和删除时需要移动大量的元素。所以我们就想到用链式存储结构来解决这个问题,就是让上一个元素存储下一个元素的地址,方便找到。这样所有元素就都可以通过遍历找到。这篇博客就来说一下单链表的简单实现。
一、单链表的定义
因此,为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。
n个结点链结成一个链表,即为线性表(a1, a2… an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表。如下图所示:
在这里插入图片描述
我们把链表中第一个结点的存储位置叫头指针。为了方便操作会在单链表的第一个结点前设一个结点叫头结点。如下图所示:
在这里插入图片描述
二、头指针和头结点的异同
1、头指针:
(1)头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针
(2)头指针具有标识作用,所以常用头指针冠以链表的名字
(3)无论链表是否为空,头指针均不为空。头指针是链表的必要元素
2、头结点:
(1)头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域般无意义(也可存放链表的长度)
(2)有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其它结点的操作就统一了
(3)头结点不定是链表必须要素
三、单链表的基本实现
1、初始化(InitList)

void InitList(List plist)//初始化
{
	assert(plist !=NULL);
	if(plist==NULL)
	{
	return;
	}
	plist->next==NULL;
}

2、插入元素(Insert)
(1)声明结点p指向链表第一个结点;
(2)当p!=NULL时,就遍历链表,让p的指针向后移动,不断指向下一个结点,i++;
(3)若到链表末尾p为空,则说明第i个元素不存在;
(4) 否则查找成功,在系统中生成一个空结点q;
(5) 将数据元素val赋值给q->data;
(6) 单链表的插入标准语句q->next=p->next; p->next=q;
(7) 返回成功。

//第一个数据节点的下标为0
bool Insert(List plist,int pos,int val)
{
	int i=0;
	Node *p;
	for(p=plist,i=0;p!=NULL&&i<pos;i++,p=p->next)
	{
	;
	}
	if(i<pos)//没有pos下标
	{
	return false;
	}
	Node *q=(Node *)malloc(sizeof(Node));
	q->data=val;
	//将q插入在p的后面
	q->next=p->next;
	p->next=q;
	return true;
}

3、单链表的删除( Delete)
(1)声明一结点p指向链表的第一个结点,初始化j从1开始。
(2)当j<i时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;
(3)若到链表末尾p为空,则说明第i个元素不存在;
(4)否则查找成功,将欲删除的结点p->next赋值给q;
(5)单链表的删除标准语句p->next=q->next;
(6)将q结点中的数据赋值给key,作为返回;
(7)释放q结点;

bool Delete(List plist,int key)
{
    int j;
	List p,q;
	p=*L;
	j=1;
	while(p->next && j<1)
	{
	p=p->next;
	++j;
	}
	if(!(p->next)|| j>1)
		return false;
	q=p->next;
	p->next =q->next;
	key=q->data;
	free(q);
	return true;
}

4、单链表的创建—头插(Insert_head)
从创建一个空表开始,生成新结点,将读入的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头结点,知道读入结束时停止。

bool Insert_head(List plist,int n)
{
    List p;
    List q = plist;
    int a;
    for(int i=0;i<n;i++)
    {
        p = (List)malloc(sizeof(Node));
        scanf("%d",&a);
        p->data = a;
        p->next = q->next;//将头指针所指向的下一个结点的地址,赋给新创建结点的next 
        q->next = p;//将新创建的结点的地址赋给头指针的下一个结点
    }
    return true; 
} 

4、单链表的创建—尾插
将新结点插入到当前单链表的表尾,增加一个尾指针r,指向当前链表的表尾

bool  Insert_tail(List plist,int n)
{
    List p,r;
    r = plist;
    int a;
    for(int i=0;i<n;i++)
    {
        p = (List)malloc(sizeof(Node));//开辟新的结点
        scanf("%d",&a);
        p->data = a;//新结点的数据域赋值
        r->next = p;
        r = p; 
    }
   r->next = NULL;
    return true;
} 

5、单链表的整表删除(ClearList)
(1)声明一结点p和q;
(2)将第一个结点赋值给p;
(3)循环:
将下一结点赋值给q; 释放p;将q赋值给p。

bool ClearList (List *L)
{
   LinkList p,q;
   p=(*L) ->next;//p指向第一个结点
   while (p)
  {
    q=p->next;
    free (p);
    p=q;
  }
   (*L)->next=NULL;//头指针的指针域指为空
   return true;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值