数据结构:线性表的链式存储结构_单链表

本文详细介绍了单链表的存储结构定义、头指针与头结点的概念及其作用,并提供了单链表基本操作的代码实现,包括创建结点、连接结点、尾部插入结点、删除结点、打印结点及链表等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.单链表的存储结构定义

     单链表:由n个结点链接成的,结点由数据域和指针域两部分组成,指针指向链表的下一个结点。
     头指针:我们把链表中的第一个结点的存储位置,整个链表的存取就必须是从头指针开始进行了。同时,我们规定链表的最后一个结点的指针域为NULL。
      头结点:有时为了操作方便,会在单链表的第一个结点前附设一个结点,该节点就是头结点。头结点的数据域可以不存储任何信息,也可存储如线性表长度等附加信息,头结点的指针域指向第一个结点的指针。

2.头指针和头结点的连续

      头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针。具有标识作用,所以常用头指针来表示链表的名字。无论链表是否为空,头指针均不为空。头指针是链表的必要元素
       头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义。有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作就统一了。头结点不是链表的必要元素


3.单链表的基本操作

存储结构的定义和函数的声明
//线性表的单链表存储结构
struct ListNode
{
	int m_nValue;
	ListNode* m_pNext;
};

//创建一个结点
ListNode* CreateListNode(int value);

//连接结点
void ConnectListNodes(ListNode* pCurrent, ListNode* pNext);

//尾部插入一个结点
void AddToTail(ListNode** pHead,int value);

//删除一个结点
void RemoveNode(ListNode** pHead,int value);

//打印结点
void PrintListNode(ListNode* pNode);

//打印链表
void PrintList(ListNode* pHead);

//销毁链表
void DestroyList(ListNode* pHead);


函数的定义
#include<iostream.h>
#include<stdlib.h>
#include"List.h"

//创建一个结点
ListNode* CreateListNode(int value)
{
	ListNode* pNode=new ListNode();
	if(pNode==NULL)
	{
		cout<<"创建结点失败!"<<endl;
		return NULL;
	}
	pNode->m_nValue=value;
	pNode->m_pNext=NULL;
	return pNode;
}

//连接结点
void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)
{
	if(pCurrent==NULL)
	{
		cout<<"当前结点不存在!"<<endl;
		return;
	}
	pCurrent->m_pNext=pNext;
}

//尾部插入节点
void AddToTail(ListNode** pHead,int value)
{
	if(pHead==NULL)
		return;
	ListNode* pNew=new ListNode();
	pNew->m_nValue=value;
	pNew->m_pNext=NULL;
	if(*pHead==NULL)
		*pHead=pNew;
	else
	{
		ListNode* pNode=*pHead;
		while(pNode->m_pNext!=NULL)
			pNode=pNode->m_pNext;
		pNode->m_pNext=pNew;
	}
}

//删除一个结点
void RemoveNode(ListNode** pHead,int value)
{
	if(pHead==NULL||*pHead==NULL)
		return;
	if((*pHead)->m_pNext==NULL&&(*pHead)->m_nValue==value)//一个结点
	{
		delete (*pHead);
		*pHead=NULL;
		return;
	}
	ListNode* pToBeDeleted;
	ListNode* pNode=*pHead;
	while(pNode->m_pNext->m_pNext!=NULL)
	{
		if(pNode->m_pNext->m_nValue!=value)
			pNode=pNode->m_pNext;
		else
		{
			pToBeDeleted=pNode->m_pNext;
			pNode->m_pNext=pNode->m_pNext->m_pNext;
			delete pToBeDeleted;
			pToBeDeleted=NULL;
			return;
		}
	}
}

//打印结点
void PrintListNode(ListNode* pNode)
{ 
    if(pNode == NULL)
    {
        cout<<"结点为空!"<<endl;
    }
    else
    {
        cout<<"结点值为:"<< pNode->m_nValue<<endl;
    }
}

//打印链表
void PrintList(ListNode* pHead)
{
    cout<<"开始打印链表"<<endl;
    
    ListNode* pNode = pHead;
    while(pNode != NULL)
    {
        cout<<pNode->m_nValue<<" ";
        pNode = pNode->m_pNext;
    }

    cout<<"打印链表结束"<<endl;
}

//销毁链表
void DestroyList(ListNode* pHead)
{
	if(pHead==NULL)
		return;
	ListNode* pCur=pHead;
	while(pCur!=NULL)
	{
	  pHead=pHead->m_pNext;
	  delete pCur;
	  pCur=pHead;
	}
}

这些代码是我也是参考了很多资料的,如有问题大家可以发评论,我们共同交流。

(1)用带表头的链表存放输入的数据,每读入一个数,按升序顺序插入到链表中,链表中允许两个结点有相同值。链表的头结点存放链表后面的结点个数,初始化时就生成头结点(初值为0)。链表翻转是把数据逆序(变成降序),注意,头结点不动。翻转后要再翻转一次,恢复升序后才能插入新元素,否则会出错。 (2)先定义堆栈的几个基本操作,再设计一主函数利用堆的操作完成以下功能:假设一个算术表达式中可以包含三种括号:()[]{},且这三种括号可以按任意次序嵌套使用(如:...[...{...}...[...]...]...(...))。编写判别给定表达式中所含括号是否正确配对出现的算法,已知表达式已存入数据元素为字符的单链表中。 (3)先定义队列的几个基本操作,再设计一主函数利用队列的操作完成以下功能:键盘输入的字符可以临时存入键盘的缓冲区中。为了充分利用缓冲区的空间,往往将缓冲区设计成链式循环队列的结构,并为循环队列结构的缓冲区设置一个队首指针和一个队尾指针。每输入一个字符到缓冲区中,就将尾指针后移,链入缓冲区的循环队列之中;每输出一个字符号,就将队头指针前移,将它从缓冲队列中删除。假设有两个进程同时存在于一个应用程序中,第一个进程连续在屏幕上显示字符“X”,第二个进程不断检查键盘上是否有输入,若有则读入用户键入的字符,将其保存到键盘缓冲区中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值