线性表学习归纳总结三:线性表链式存储 不带头结点

线性表的链式存储,需要考虑链表是否带有头指针,是不是循环链表,是不是双链表

带有头结点的单链表

循环链表

双链表

  • 不带有头结点的单链表,头指针head直接指向第一个结点,带有头结点的单链表,head指向头结点,头结点的存储结构和后续结点一样,但只使用了头结点的next指针域。
  • 链表存储结构

    typedef int datatype;
    typedef struct link_node{
    	datatype info;
    	struct link_node *next;		//指向下一个结点的link_node指针
    }node;
  • 基本运算实现函数
    node *init();	//建立一个空的单链表
    void display(node *head);	//输出单链表中各个结点的值
    node *find(node *head,int i);	//在单链表中查找第i个结点的存放地址
    node *insert(node *head, datatype x, int i);	//在第i个结点后插入值为x的新结点
    node *dele(node *head, datatype x);	//在单链表中删除一个值为x的结点
  • 具体实现函数
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include "slnklist.h"
    /************************************************************************/
    /* 函数功能:建立一个空的单链表,单链表的初始化   */
    /* 函数参数: 无  */
    /* 函数返回值: 指向node类型变量的指针  */
    /* 文件名: slnklist.c ,函数名:init() */
    /************************************************************************/
    node *init()
    {
    	return NULL;
    }
    
    /************************************************************************/
    /* 函数功能: 输出单链表中各个结点的值  */
    /* 函数参数:  指向node类型变量的指针head*/
    /* 函数返回值: 空  */
    /* 文件名: slnklist.c ,函数名: display()*/
    /************************************************************************/
    void display(node *head)
    {
    	node *p;
    	p = head;
    	if (!p)
    	{
    		printf("\n单链表是空的!");
    	}
    	else
    	{
    		printf("\n单链表各个结点的值为:\n");
    		while(p)
    		{
    			printf("%5d",p->info);
    			p = p->next;
    		}
    	}
    }
    
    /************************************************************************/
    /* 函数功能: 在单链表中查找第i个结点的存放地址  */
    /* 函数参数:  指向node类型变量的指针head,int型变量i */
    /* 函数返回值:  指向node类型变量的指针 */
    /* 文件名: slnklist.c ,函数名: find()*/
    /************************************************************************/
    node *find(node *head,int i)
    {
    	int j=1;		//结点从1开始计数
    	node *p = head;
    	if (i<1)
    	{
    		return NULL;
    	}
    	while (p && i!=j)
    	{
    		p = p->next;
    		j++;
    	}
    	return p;
    }
    /************************************************************************/
    /* 函数功能:  单链表第i个结点后插入值为x的新结点 */
    /* 函数参数:  指向node类型变量的指针head,datatype类型变量x,int型变量i	*/
    /* 函数返回值:  指向node类型变量的指针 */
    /* 文件名: slnklist.c ,函数名: insert()*/
    /************************************************************************/
    node *insert(node *head, datatype x, int i)
    {
    	node *p,*q;
    	q = find(head,i);	//第i个结点的存放地址
    	if (!q && i != 0)
    	{
    		printf("\n找不到第%d个结点,不能插入%d!",i,x);
    	}
    	else
    	{
    		p = (node *)malloc(sizeof(node));	//分配空间
    		p->info = x;		//设置新结点
    		if (i==0)	//插入点作为单链表的第一个结点
    		{
    			p->next = head;
    			head = p;
    		}
    		else
    		{
    			p->next = q->next;
    			q->next = p;
    		}
    	}
    	return head;
    }
    /************************************************************************/
    /* 函数功能: 在单链表中删除一个值为x的结点 */
    /* 函数参数:  指向node类型变量的指针head,datatype类型变量x */
    /* 函数返回值:  指向node类型变量的指针 */
    /* 文件名: slnklist.c ,函数名: dele()*/
    /************************************************************************/
    node *dele(node *head, datatype x)
    {
    	node *pre=NULL, *p;
    	if (!head)
    	{
    		printf("单链表是空的!");
    		return head;
    	}
    	p = head;
    	while (p && p->info!=x)	//没有找到并且没有找完
    	{
    		pre=p;
    		p=p->next;
    	}
    	if (!pre && p->info==x)//要删除的是第一个结点
    	{
    		head = p->next;
    	}
    	else
    		pre->next = p->next;
    	free(p);
    	return head;
    }

  • main验证函数
    #include <stdio.h>
    #include <stdlib.h>
    #include "slnklist.h"
    
    void main(void)
    {
    	node slnklist;
    	node *p_slnklist;
    	//初始化单链表
    	p_slnklist = init();
    	//利用插入方法建立一个链表
    	int getin;
    	int num = 0;
    	puts("输入插到链表末尾的值");
    	while ((scanf("%d", &getin))==1)
    	{
    		p_slnklist = insert(p_slnklist, getin,num);
    		num++;
    	}
    	display(p_slnklist);	//输出链表结点值
    
    	//查找第i个结点的存放地址
    	node *q;
    	int i;
    	puts("\n查找第i个结点的存放地址,输入i值");
    	while((scanf("%d", &i))==1)
    	{
    		q = find(p_slnklist, i);
    		printf("第%d个结点值是%d,存放地址是%d\n", i, q->info, q);
    		puts("查找第i个结点的存放地址,输入i值");
    	}	
    
    	//在第i个结点后面插入值为x的新结点
    	int x;
    	puts("第i个结点后面插入值为x的新结点,输入i和x");
    	while((scanf("%d,%d", &i, &x))==2)
    	{
    		p_slnklist = insert(p_slnklist, x, i);
    		display(p_slnklist);
    		puts("\n第i个结点后面插入值为x的新结点,输入i和x");
    	}
    
    	//在单链表中删除一个值为x的结点
    	puts("输入带删除的结点值x");
    	while ((scanf("%d", &x))==1)
    	{
    		p_slnklist = dele(p_slnklist, x);
    		display(p_slnklist);
    		puts("\n输入带删除的结点值x");
    	}
    	system("pause");
    }

    运行结果

Ps:
  1. 单链表中查找第i个结点的存放地址时候,需要特别区分,i是否小于1,以及结点计数是否是从1开始
  2. 单链表第i个结点插入值为x的新结点,利用查找第i个结点地址的函数进行定位,需要注意,当find函数返回null时候,要判断是因为i为0,还是因为i超出当前链表大小,i值超出链表大小处理如下
    if (!q && i != 0)
    {
    <span style="white-space:pre">	</span>printf("\n找不到第%d个结点,不能插入%d!",i,x);
    }
  3. 特别注意,插入结点作为链表第一个结点时候的处理
    if (i==0)	//插入点作为单链表的第一个结点
    {
    	p->next = head;
    	head = p;
    }
    else
    {
    	p->next = q->next;
    	q->next = p;
    }
  4. 删除结点时候,需要判断链表是否为空;不为空时候,查找值为x的结点,并在查找过程中,保存该结点的前驱结点的指针;找到值为x的结点后,需要判断该结点是否为链表的第一个结点
    if (!pre && p->info==x)//要删除的是第一个结点
    {
    	head = p->next;
    }
    else
    	pre->next = p->next;
    free(p);



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值