不带头结点的单链表实现示例(C语言)

不带头结点的单链表实现示例(C语言)

大部分代码为参考代码,在此基础上做了以下修改
代码较长,需耐心观看
其中   LinkList*  等价于 Lnode**       这俩个使用哪一个都可以,前提是在声明结构体的时候要加上。
修改的地方有:
	在指定位置插入一个元素
	删除指定位置的元素
	打印链表更加合理

心得:
最重要的还是懂得原理
如何创建一个不带头结点的链表
如何实现增、删、改、查、打印等功能
重点还是原理。
不行就画图,慢慢理清逻辑,下一次不就会了嘛
加油!

#include<stdio.h>
#include<assert.h>
#include<malloc.h>

//不带头节点的单链表

typedef int DataType;   //数据类型

typedef struct LinkNode
{
	DataType _data;          //值域
	struct LinkNode *_pNext;  //指针域
}Lnode, *LinkList;

void LinkListInit(LinkList* pHead);   //链表初始化

Lnode* LinkListCreatNode(DataType data);  //创建新节点

void LinkListDestoryNode(LinkList* pHead); //销毁节点

void LinkListPrint(LinkList* pHead);   //遍历打印节点

void LinkListPushBack(LinkList* pHead, DataType data);  //尾插

void LinkListPopBack(LinkList* pHead);  //尾删

void LinkListPushFront(LinkList* pHead, DataType data);  //头插

void LinkListPopFront(LinkList* pHead);  //头删

int LinkListSize(LinkList* pHead);   //求链表长度

void LinkListDestory(LinkList* pHead);   //销毁链表

void LinkList_Insert_anysite(LinkList* pHead, DataType data, DataType pos);  //任意位置插入

void LinkList_del_anysite(LinkList* pHead,  DataType pos);  //任意位置删除

int LinkListEmpty(LinkList* pHead);   //判空


void LinkListInit(LinkList* pHead)   //链表初始化
{
	assert(pHead);
	*pHead = NULL;
}

Lnode* LinkListCreatNode(DataType data)  //创建新节点
{
	Lnode* pNewNode = (Lnode*)malloc(sizeof(Lnode));
	assert(pNewNode);

	pNewNode -> _data = data;
	pNewNode -> _pNext = NULL;
	return pNewNode;
}

void LinkListDestoryNode(LinkList* pHead) //销毁节点
{
	free(pHead);
	*pHead = NULL;
}

void LinkListPrint(LinkList* pHead)   //遍历打印节点
{
	Lnode* pCur = *pHead;
	for(pCur; pCur != NULL; pCur = pCur -> _pNext)
	{
		if(pCur -> _pNext != NULL)
		{
			printf("%d----->", pCur -> _data);
		}
		else
		{
			printf("%d\n", pCur -> _data);
		}
	}
}

void LinkListPushBack(LinkList* pHead, DataType data)  //尾插
{
	Lnode* NewNode = LinkListCreatNode(data);
	assert(pHead);
	 //如果链表为空,则直接让头指针指向新申请的节点即可
	if(*pHead == NULL)
	{
		*pHead = NewNode;
		return;
	}
	//否则从头开始遍历链表,直到当前节点的指针域指向NULL,然后让当前节
    //点的指针域指向新申请的节点即可
	Lnode* pTail = *pHead;
	while(pTail -> _pNext)
	{
		pTail = pTail -> _pNext;
	}
	pTail -> _pNext = NewNode;
}

void LinkListPopBack(LinkList* pHead)  //尾删
{
	assert(pHead);
	if(*pHead == NULL)
	{
		printf("链表为空!,删除失败!\n");
		return;
	}
   //如果当前只有一个结点,则释放该结点,
    //并将头指针指向NULL,防止出现野指针--相当于销毁结点
    if((*pHead) -> _pNext == NULL)
    {
    	free(pHead);
    	*pHead = NULL;
    }
     //定义两个指针,依次向后走
    //pTail不为空时,将其前一个结点指针pPreTail赋给pTail
    //当pTail为空时,释放pTail,pPreTail指向NULL
    Lnode* pTail = *pHead;
    Lnode* pPreTail = NULL;
    while(pTail -> _pNext)
    {
    	pPreTail = pTail;
    	pTail = pTail -> _pNext;
    }
    free(pTail);
    pPreTail -> _pNext = NULL;
}

void LinkListPushFront(LinkList* pHead, DataType data)  //头插
{
	assert(pHead);
	Lnode* NewNode = LinkListCreatNode(data);
	NewNode -> _pNext = (*pHead);
	*pHead = NewNode;
}

void LinkListPopFront(LinkList* pHead)  //头删
{
	Lnode* pDel = NULL;
	assert(pHead);
	if((*pHead) == NULL)
	{
        printf("链表为空!无法删除!\n");
        return;
	}
	pDel = *pHead;
	*pHead = pDel -> _pNext;
	free(pDel);
}

int LinkListSize(LinkList* pHead)   //求链表长度
{
	assert(pHead);
	Lnode* pSize = *pHead;
	int count = 0;
	while(pSize != NULL)
	{
		pSize = pSize -> _pNext;
		count++;
	}
	return count;
}

void LinkListDestory(LinkList* pHead)   //销毁链表
{
	assert(pHead);
	Lnode* pDpre = NULL;
	Lnode* pD = *pHead;
	 //定义两个指针同时向链尾走,pD不为空时,用pDpre标记pD
    //pD不断向后移同时释放pDpre,直至将整个链表结点全部释放
    while(pD)
    {
    	pDpre = pD;
    	pD = pD -> _pNext;
    	free(pDpre);
    }
     //切记将头指针指向空,不然将变成野指针
    *pHead = NULL;
}

void LinkList_Insert_anysite(LinkList* pHead, DataType data, DataType pos)  //任意位置插入
{
	assert(pHead);
	Lnode* pNewNode = LinkListCreatNode(data);

	//链表为空
	if(*pHead == NULL)
	{
		*pHead = pNewNode;
		return;
	}
	//在头部插入
	if(pos == 1)
	{
		LinkListPushFront(pHead, data);
		return;
	}
	if(pos > LinkListSize(pHead))
	{
		printf("插入位置有误!\n");
		return;
	}
    Lnode* pCur = *pHead;
    int i = 2;
    while(pCur -> _pNext != NULL)
    {
    	if(i == pos)
    	{
    		pNewNode -> _pNext = pCur -> _pNext;
    		pCur -> _pNext = pNewNode;
    	}
    	pCur = pCur -> _pNext;
    	i++;
    }
    return;
}

void LinkList_del_anysite(LinkList* pHead, DataType pos)  //任意位置删除
{
	assert(pHead);

    //考虑链表为空
    if ((*pHead) == NULL)
    {
        printf("链表为空!无法删除!\n");
        return;
    }

    if (pos == 1)
    {
        LinkListPopFront(pHead);
        return;
    }

    if(pos > LinkListSize(pHead))
	{
		printf("插入位置有误!\n");
		return;
	}

    int i = 1;
    Lnode* pE = *pHead;
    while ( pE != NULL)
    {
        if (pE->_pNext != NULL)
        {
            i++;
            if(i == pos)
            {
            	Lnode* p = pE->_pNext;
            	pE -> _pNext = pE -> _pNext -> _pNext;
            	free(p);
            }
            return;
        }
        pE = pE->_pNext;
        i++;    
    }
    return;
}

int LinkListEmpty(Lnode** pHead)   //判空
{
	assert(pHead);
    return ((*pHead) == NULL);
}

void LinkListTest()
{
    LinkList p;
    LinkListInit(&p);
    for(int i =1; i < 6; i++)
    {
    	LinkListPushBack(&p, i);
    }
    LinkListPushBack(&p, 5);
    LinkListPrint(&p);

    LinkListPopBack(&p);
    LinkListPrint(&p);

    LinkListPushFront(&p, 5);
    LinkListPushFront(&p, 6);
    LinkListPrint(&p);

    LinkListPopFront(&p); 
    LinkListPopFront(&p);
    LinkListPrint(&p);

    printf("链表长度为%d\n", LinkListSize(&p));

    LinkList_Insert_anysite(&p,6,4);
    LinkListPrint(&p);

    LinkList_del_anysite(&p,2);
    LinkListPrint(&p);

}
int main()
{
	LinkListTest();
}

结果图:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

trust Tomorrow

感谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值