带头节点的单链表

特点

  1. 有一个head指针变量,它存放头结点的地址,称之为头指针。
  2. 头节点的指针域head->next,存放首元结点的地址。
  3. 每个节点都包含一个数据域和指针域,数据域存放数据,指针域存放下一节点的地址。
  4. 最后一个结点不在指向其他结点,它的指针域存放空指针。
  5. 链表依靠指针相连不需要占用一块连续的内存空间。
  6. 随着处理数据量的增加,链表可以无限制的延长。在插入和删除操作中,只需修改相关节点指针域的链接关系,不需要大量的改变数据的实际储存位置。链表的使用,可以使程序的内存利用率和时间效率大大增加。

    单链表初始化

    链表结点数据类型选用结构体类型(C语言允许结构体类型递归定义)。 例如建立一个链表表示一个班级,其中链表的结点表示学生。

    typedef struct node
    {
    	char name[20];
    	int number;           //数据域
    	struct node *next;    //指针域
    }Node,*LinkList;
    

    其中Node是结构体类型,LinkList是结构体指针类型。

    单链表的初始化就是创建一个头节点。

    LinkList Init()
    {
    	LinkList head;
    	head = (Node*)malloc(sizeof(Node));
    	head->next = NULL;
    	return head;
    }
    

    单链表的建立

    1、尾插法

    在尾部插入新结点建立单链表。 从一个空表开始,重复读入数据,将读入数据存入新结点的数据域中,然后将新结点差入到当前链表的表尾上,直至读入结束标志为止。

    void Build(LinkList head)
    {
    	LinkList r, s;
    	char name[20];
    	int number;
    	r = head;
    	printf("请输入学生的姓名和学号\n");
    	while (1)
    	{
    		scanf("%s%d", name,&number);
    		if (number == 0)
    			break;
    		s = (Node*)malloc(sizeof(Node));
    		s->number = number;
    		strcpy(s->name, name);
    		r->next = s;
    		r = s;
    	}
    	r->next = NULL;
    }
    

    头插法

    在单链表头部插入新结点。 从一个空表开始重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头结点之后,直至读入结束标志为止。

    void Build(LinkList head)
    {
    	LinkList s;
    	int number;
    	char name[20];
    	printf("请输入学生姓名和学号\n");
    	while (1)
    	{
    		scanf("%s%d", name, &number);
    		if (number == 0)
    			break;
    		s = (Node*)malloc(sizeof(Node));
    		s->number = number;
    		strcpy(s->name, name);
    		s->next = head->next;
    		head->next = s;
    	}
    }
    

    单链表的遍历

    定义一个临时指针p,使其指向链表的首元结点。在while循环中,每输出一个结点的内容,就移动p至下一个结点。

    void OutPut(LinkList head)
    {
    	LinkList p=head->next;
    	printf("学生信息如下\n");
    	while (p)
    	{
    		printf("姓名:%s  ", p->name);
    		printf("学号:%d\n", p->number);
    		p = p->next;
    	}
    }
    

    单链表的查询

    定义指针变量p,使其指向链表的首元结点。如果某结点的值和给定值不同,则移动p这下一个结点。直至某结点的值和给定的值相同,返回该结点地址。

    LinkList Search(LinkList head, char name[])
    {
    	LinkList p = head->next;
    	while (p)
    	{
    		if (strcmp(p->name, name) != 0)
    			p = p->next;
    		else
    			break;
    	}
    	if (p == NULL)
    		printf("EOROR\n");
    	return p;
    }
    

    单链表的插入

    从链表的头结点开始,找到链表第i-1个结点的地址p,在第i-1个结点后插入新结点。 插入时,先将新结点的指针指向第i个结点,再将第i-1个结点的指针指向新结点。

    void Inser(LinkList head,int i)
    {
    	LinkList p = head, s;
    	int j=0;
    	while (j < i - 1 && p)
    	{
    		p = p->next;
    		j++;
    	}
    	if (p)
    	{
    		printf("请输入待添加的学生的姓名和学号\n");
    		s = (Node*)malloc(sizeof(Node));
    		scanf("%s%d", s->name, &s->number);
    		s->next = p->next;
    		p->next = s;
    	}
    }
    

    单链表的删除

    首先利用循环找到要删除的结点p和p之前的结点q(将Search函数稍作改变)。如果该节点存在,则连接待删除结点两边的结点(q->next = p->next),并使用free函数将p指向的内存空间释放。

    void Delete(LinkList head,char name[20])
    {
    	LinkList p = head->next;
    	LinkList q = p->next;
    	while (1)
    	{
    		if (strcmp(p->name, name) != 0)
    		{
    			q = p;
    			p = p->next;
    		}
    		else
    			break;
    	}
    	if (q== NULL || p == NULL)
    		printf("EORROR\n");
    	else
    	{
    		q->next = p->next;
    		free(p);
    	}
    }
    

    单链表的长度

    从首元点开始,依次遍历链表的所有结点,并同时统计结点个数。最后返回结点个数。

    int Length(LinkList head)
    {
    	LinkList p = head->next;
    	int count = 0;
    	while (p)
    	{
    		p = p->next;
    		count++;
    	}
    	return count;
    }
    
上一篇:链表的理解


下一篇:2.30