带头结点单链表、不带头结点单链表(头指针单链表)

本文详细探讨了头结点与头指针在单链表实现中的差异,包括它们的概念、作用以及在各种操作如插入、删除、查找等中的实现方式。通过实例展示了头结点如何存储链表长度,以及头指针如何简化操作。同时,对比了头结点单链表和头指针单链表在空间效率和操作复杂度上的特点。
摘要由CSDN通过智能技术生成

1、头结点和头指针的区别

1.1区别:
头指针表明了链表的结点,可以唯一确定一个单链表。
头指针指向链表的第一个结点,其记录第一个存储数据的结点的地址。
头结点是点链表的第一个结点,若单链表有头结点,则头指针指向头结点;若单链表没有头结点,则指针指向第一个结点。
一个单链表可有没有头结点,但不能没有头指针。
头结点的数据域可以不存储任何数据。

1.2记录链表的类型不同:
头指针是一个4字节的指针,记录第一个存储数据的结点的地址。
头结点是一个结构体变量,使用这个变量的next域来记录第一个存储数据的结点的地址,头结点的data域可以使用联合体的方式记录链表的长度。

1.3各个操作方法的定义不同
如果是头指针实现,则方法中国接受这个链表的类型必须是二级指针。
头指针实现使用一级指针就OK。
在这里插入图片描述

2、头结点单链表

链表和顺序表的区别:
(1)链表在逻辑存储上是连续的,在物理存储上是不连续的。
(2)单链表属于链表中的一种,每一个存储数据的节点除了存储数据本身之外,还要存储其直接后继结点的地址。
在这里插入图片描述
例:32位系统存储10个整形(int 4个字节)数据:
顺序表存储 :总共需要堆区空间:40个字节
单链表存储: 总共需要堆区空间:80个字节

单链表的实现

头结点:
在这里插入图片描述
头指针——在实现代码中会使用二级指针
在这里插入图片描述
方法的声明:

#include<stdio.h>
typedef int DataType;

typedef struct Node
{
	//数据类型
	union//结合体、联合体
	{
		DataType data;//存储元素
		int length;//存储元素个数
	};
	//结点指针类型
	struct Node *next; 
}LinkList;

//初始化
void InitLinkList(LinkList *head);

//销毁
void DestroyLinkList(LinkList *head);

//按位置插入插入
bool InsertPos(LinkList *head,DataType value,int pos);

//头插
bool InsertFront(LinkList *head,DataType value);

//尾插
bool InsertRear(LinkList *head,DataType value);

//按位置删除
bool DeletePos(LinkList *head,int pos);

//头删
bool DeleteFront(LinkList *head);

//尾删
bool DeleteRear(LinkList *head);

//按值删除
bool DeleteValue(LinkList *head,DataType value);

//判空
bool IsEmpty(LinkList *head);

//求长度
int GetLength(LinkList *head);

//输出
bool PrintLinkList(LinkList *head);


方法的实现:

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
#include"head.h"

static LinkList *ApplyNode(DataType value,LinkList *point )
{
       LinkList *new_node=(LinkList *)malloc(sizeof(LinkList));
       if(new_node==NULL) return NULL;
       new_node->data=value;
       new_node->next=point;
    
    return new_node;
}

void InitLinkList(LinkList *head)
{
	 
     if(head==NULL) exit(0);
     
	
    head->length=0;
     head->next=NULL;
}




int GetLength(LinkList *head)
{
    if(head==NULL) exit(0);
    return head->length;
}

bool InsertPos(LinkList *head,DataType value,int pos)
{
     if(head==NULL) exit(0);
     if(pos<0||pos>GetLength(head)) return false;
     
     LinkList *p=head;
     while(pos)
    {
          p=p->next;
          pos--;
         
    }
    LinkList *new_node=ApplyNode(value,p->next);//生成新的结点
    if(new_node==NULL) return false;
           
    p->next=new_node;
    head->length++;
    return true;
     
}

bool InsertFront(LinkList *head,DataType value)
{
     if(head==NULL) exit(0);
     LinkList *new_node=ApplyNode(value,head->next);
     if(new_node==NULL) return false;
      
     head->next=new_node;
     head->length++;
     return true;
}

bool InsertRear(LinkList *head,DataType value)
{
     if(head==NULL) exit(0);
    return InsertPos(head,value,GetLength(head));
}

bool DeletePos(LinkList *head,int pos)
{
     if(head==NULL) exit(0);
     if(pos<0||pos>=head->length) return false;
     LinkList *p=head;
     while(pos)
     {
        p=p->next;
        pos--;
     }
     LinkList *q=p->next;
     p->next=q->next;
     free(q);
     head->length--;
     return true;
}

bool DeleteFront(LinkList *head)
{
     if(head==NULL) exit(0);
     return DeletePos(head,0);
}

bool DeleteRear(LinkList *head)
{
     if(head==NULL) exit(0);
     return DeletePos(head,GetLength(head)-1);
}

bool DeleteValue(LinkList *head,DataType value)
{
     if(head==NULL) exit(0);
     LinkList *p=head;
     LinkList *q=p->next;
     while(q!=NULL)
    {
       if(q->data==value)
        {
            p->next=q->next;
            free(q);
            q=p->next;
            head->length--;
        }
        else
        {
            p=q;
            q=q->next;
        }
    }
    return true;
}

bool IsEmpty(LinkList *head)
{ 
     if(head==NULL) exit(0);
     return head->length==0;
}

bool PointLinkList(LinkList *head)
{
     if (head == NULL) exit(0);

	LinkList *p = head->next;

	while (p != NULL)
	{
		printf("%d  ", p->data);
		p = p->next;
	}

	printf("\n");
}
void DestroyLinkList(LinkList *head)
{
     if(head=NULL) exit(0);
     while(IsEmpty(head)!=NULL)
	 {
      DeleteFront(head);

	 }
}

//找到第K个结点
LinkList *FindK(LinkList *head, int k)  //  0< k <= length
{
	if (head == NULL)  return NULL;

	if (k <= 0 || k > head->length)  return NULL;

	int pos = head->length - k + 1;

	LinkList *p = head;

	while (pos)
	{
		p = p->next;
		pos--;
	}
	
	return p;
}

//  不能直接获得length的情况
LinkList *FindOfK2(LinkList *head, int k)
{
	if (head == NULL)  return NULL;

	if (k <= 0)  return NULL;

	LinkList *p = head;

	while (k && p != NULL)
	{
		p = p->next;
		k--;
	}

	if (p == NULL)  return NULL;

	LinkList *q = head;
	while (p != NULL)
	{
		p = p->next;
		q = q->next;
	}

	return q;
}

//O(1)删除非尾结点p
bool DeletePos1(LinkList *head,int pos)
{
    if(head==NULL) return false;
    if(pos<0||pos>=head->length) return false;
    LinkList *p=head;
    while(pos)
    {
        p=p->next;
        pos--;
    }
    LinkList *q=p->next;
    p->next=q->next;
    free(q);
    head->length--;
    return true;
    
}

//将单链表逆置  -- 结点逆置
void Reverse(LinkList *head)
{
    if(head==NULL) return;
    LinkList *p=NULL;
    LinkList *q=head->next;
    LinkList *s=q->next;
	
    while(q!=NULL)
    {
        q->next=p;
        p=q;
        q=s;
        if(s!=NULL) s=s->next;
    }
    head->next=p;
}
//判断两个结点是否相交,返回相交的第一个结点
LinkList *IsIntersect(LinkList *head1,LinkList *head2)
{
    if(head1==NULL||head2==NULL) return false;
    LinkList *p=head1;
    LinkList *q=head2;
    if(head1->length>head2->length)
    {
        for(int i=0;i<head1->length-head2->length;i++)
        {
            p=p->next;
        }
    }
    else
    {
        for(int i=0;i<head2->length-head1->length;i++)
        {
            q=q->next;
        }
    }
    while(p!=q)
    {
        p=p->next;
        q=q->next;
    }
	
    return p;
}

LinkList *IsIntersect2(LinkList *head1, LinkList *head2)
{
	if (head1 == NULL || head2 == NULL)  return NULL;

	LinkList *p = head1;
	LinkList *q = head2;

	while (p != q)
	{
		if (p != NULL) p = p->next;
		else  p = head2;
		if (q != NULL) q = q->next;
		else q = head1;
// 		p = p != NULL ? p->next : head2;
// 		q = q != NULL ? q->next : head1;
	}

	return p;
}
//判断单链表是否有环,如果有,返回入环的第一个结点
LinkList *IsLoop(LinkList *head)
{
    if(head==NULL) return NULL;
    LinkList *fast=head;
    LinkList *slow=head;
    while(fast!=NULL&&fast->next!=NULL)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow) break;
    }
    LinkList *p=fast;
    LinkList *q=slow;
    while(q!=p)
    {
        p=p->next;
        q=q->next;
    }
    return p;
}

int main()
{
	LinkList list;
	InitLinkList(&list);
	InsertFront(&list,1);
	InsertPos(&list,2,1);
	InsertRear (&list,3);
	InsertRear (&list,4);
	InsertRear (&list,5);
	DeletePos(&list,1);
	printf("单链表长度为:%d\n",GetLength(&list));
	printf("第一次输出:");
	PointLinkList(&list);
	DeleteValue(&list,4);
	InsertPos(&list,2,1);
	printf("第二次输出:");
	PointLinkList(&list);
	return 0;
}

3、头指针单链表

在这里插入图片描述
方法的声明:

#include<stdio.h>
typedef  int  DataType;

typedef struct Node
{
  	DataType    data;    //   记录本结点存储的数据
    struct Node  *next;  //   记录下一个结点的地址
}LinkList;

// 初始化
void  InitLinkList(LinkList **phead);
//  插入
bool InsertLinkList(LinkList **phead, DataType value, int pos);

bool InsertLinkListHead(LinkList **phead, DataType value);

bool InsertLinkListRear(LinkList **phead, DataType value);

//  删除
bool DeleteLinkList(LinkList **phead, int pos);

bool DeleteLinkListHead(LinkList **phead);

bool DeleteLinkListRear(LinkList **phead);

//  长度
int GetLength(LinkList **phead);
//  判空
bool  Empty(LinkList **phead);
//  销毁
void  DestroyLinkList(LinkList **phead);

//  显示
void  ShowLinkList(LinkList **phead);

方法的实现:

#include "head.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>


static LinkList *ApplyNewNode(DataType value, LinkList *next)
{
	LinkList *new_node = (LinkList *)malloc(sizeof(LinkList));
	if (new_node == NULL)  exit(0);

	new_node->data = value;
	new_node->next = next;

	return new_node;
}


void  InitLinkList(LinkList **phead)  //  phead中存储的值就是main方法中的phead变量的地址
{
	if (phead == NULL)  exit(0);

	*phead = NULL;
}

int GetLength(LinkList **phead)
{
	if (phead == NULL)  exit(0);

	int length = 0;

	LinkList *p = *phead;

	while (p != NULL)
	{
		length++;
		p = p->next;
	}

	return length;
}

bool InsertLinkList(LinkList **phead, DataType value, int pos)
{
	if (phead == NULL)  exit(0);

	if (pos < 0 || pos > GetLength(phead))  return false;

	//  在头指针的后面插入新结点,头插法必须特殊处理: 因为只有在这需要修改头指针的值
	if (pos == 0)  return InsertLinkListHead(phead, value);//  头插


	LinkList *p = *phead;

	while (pos > 1)
	{
		p = p->next;
		pos--;
	}

	//  while循环结束后,就需要在p所指向的结点的后面插入新结点

	/* 
		LinkList *new_node = ApplyNewNode(value, p->next); 
		p->next = new_node;
	*/
	p->next = ApplyNewNode(value, p->next);
	return true;
}

bool InsertLinkListHead(LinkList **phead, DataType value)
{
	if (phead == NULL)  exit(0);

	*phead = ApplyNewNode(value, *phead);

	return true;
}

bool InsertLinkListRear(LinkList **phead, DataType value)
{
	if (phead == NULL)  exit(0);

	//  链表本身是空的,尾插相当于头插
	if (Empty(phead))  return InsertLinkListHead(phead, value);

	LinkList *p = *phead;

	while (p->next != NULL)  p = p->next;  //  while循环结束后,p就是最后一个结点

	p->next = ApplyNewNode(value, NULL);
	return true;
}

bool  Empty(LinkList **phead)
{
	if (phead == NULL)  exit(0);

	if (*phead == NULL)  return true;

	return false;
}



bool DeleteLinkList(LinkList **phead, int pos)
{
	if (phead == NULL)  exit(0);

	if (pos < 0 || pos >= GetLength(phead))  return false;

	if (pos == 0)  return DeleteLinkListHead(phead);

	LinkList *p = *phead;  //  p指向的是第一个数据结点

	while (pos > 1)
	{
		p = p->next;
		pos--;
	}

	//  while循环结束后,要删除的结点时p->next
	LinkList *q = p->next;
	p->next = q->next;
	free(q);
	return true;
}

bool DeleteLinkListHead(LinkList **phead)
{
	if (phead == NULL)  exit(0);

	if (Empty(phead))  return false;

	LinkList *p = *phead;

	*phead = p->next;
	free(p);
	return true;
}

bool DeleteLinkListRear(LinkList **phead)
{
	if (phead == NULL)  exit(0);

	if (Empty(phead))  return false;

	LinkList *front = NULL;
	LinkList *p = *phead;

	while (p->next != NULL)
	{
		front = p;
		p = p->next;
	}

	if (front == NULL)  return DeleteLinkListHead(phead);

	front->next = NULL;
	free(p);
	return true;
}

void  DestroyLinkList(LinkList **phead)
{
	if (phead == NULL)  exit(0);

	while (!Empty(phead))
	{
		DeleteLinkListHead(phead);
	}
}

void  ShowLinkList(LinkList **phead)
{
	if (phead == NULL)  exit(0);

	LinkList *p = *phead;

	while (p != NULL)
	{
		printf("%d  ", p->data);
		p = p->next;
	}

	printf("\n");
}

int main()
{
	LinkList *list;
	InitLinkList(&list);
	InsertLinkListHead(&list,6);
	InsertLinkListHead(&list,5);
	InsertLinkListHead(&list,4);
	InsertLinkListHead(&list,3);
	InsertLinkListHead(&list,2);
	InsertLinkListHead(&list,1);
	DeleteLinkList (&list,5);
	printf("第一次输出:");
	ShowLinkList(&list);
	InsertLinkList(&list,6,5);
	InsertLinkListRear(&list,7);
	DeleteLinkListHead(&list);
	DeleteLinkListRear(&list);
	printf("第一次输出:");
	ShowLinkList(&list);


	return 0;
}
头指针单链表操作时的转化

因为头结点实现的单链表相比于头指针实现的单链表,操作时特殊情况少一些。在实现一些有指针的单链表的操作时,可以虚拟构建出一个头结点。

bool Funaction(LinkList **phead)
{
	//虚拟出来的头结点
	LinkList *head=(LinkList *)malloc(sizeof(LinkList));
	head->next =*phead;

	LinkList *p=head;//p指向头结点
	LinkList *q=p->next;

	while(q->next!=NULL)
	{
		p=q;
		q=q->next;
	}

	p->next=q->next ;
	free(q);
	*phead=head->next;
	free(head);
}

  • 4
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值