【Data_Structure笔记2】线性表的链式存储【单链表】

/************************************************************************************************************************
文件说明:
        线性表的链式存储之【单链表】、【双链表】、【循环链表】、【静态链表】
详细说明:
        【1】由于顺序表的插入、删除操作需要大量的移动元素,而大量的移动元素这一操作会严重影响算法的性能,那么如何克服顺序表
		     操作中的这一缺点呢?这就引出了我们今天将要学习的线性表的链式存储之【单链表】。
		【2】线性表的链式存储不需要使用地址连续的的存储单元,也不需要逻辑上相邻的元素之间,物理位置上也相邻,它是通过“链”,
		     即指针建立起数据元素之间的逻辑关系,因此,对线性表的插入、删除不需要移动元素,只需要修改相应的指针即可。
		【3】链式存储:不要求逻辑上相邻的元素在物理位置上也相邻,借助指针来表示元素之间的逻辑关系,其优点是:不出出现内存的
		     碎片现象,充分利用了内存中的所有存储单元;缺点是:每个数据元素节点占用较多的存储空间,并且只能实现顺序存储,不
			 能实现【随机存取】。
		【4】顺序存储:要求逻辑上相邻的数据元素之间,物理位置上也必须相邻,元素之间的逻辑关系由存储单元之间的邻接关系表示。
		     其优点是:每个元素占用较少的存储空间,并且可以实现随机存取;缺点是:只能使用相邻的一整块存储单元,因此,可能会
			 产生较多的碎片现象。
单链表:
        【1】【单链表】:线性表的链式存储称为单链表,它是通过一组任意的存储单元来存储线性表中的数据元素的。
		【2】为了建立起数据元素之间的线性关系,对每个链表的结点,除了存放元素自身的信息之外,还需要存放一个指向其后继的指针。
		     单链表的结点一般分为两个域,【数据域】和【指针域】。
*************************************************************************************************************************/
#include<iostream>
#include<string>

using namespace std;

/*************************************************************************************************************************
单链表的11中算法:
      【1】初始化单链表的操作
	  【2】头插法建立单链表
	  【3】尾插法建立单链表
	  【4】打印单链表,单链表的遍历
	  【5】清除线性表中的所有元素,即释放单链表pHead中所有的结点,使之成为一个空表
	  【6】返回单链表的实际长度
	  【7】检查单链表是否为空,若为空,则返回1,否则返回0
	  【8】按序号查找结点值
	  【9】按值查找表结点
	  【10】插入结点操作
	  【11】删除结点操作
**************************************************************************************************************************/
typedef int ElemType;
/*************************************************************************************************************************
模块说明:
        单链表中,结点类型的描述
**************************************************************************************************************************/
typedef struct LNode
{
	ElemType       data;                                     //【1】数据域
	struct LNode* next;                                     //【2】指针域
}LNode,*LinkList;
/*************************************************************************************************************************
函数原型:
        void InitList(LinkList& pHead)
函数说明:
        【1】初始化单链表的操作
		【2】pHead是指向单链表头结点的指针,用来接收主程序中待初始化单链表的头指针变量
**************************************************************************************************************************/
void InitList(LinkList& pHead)
{
	pHead = (LinkList)std::malloc(sizeof(LNode));                            //【1】创建头结点
	pHead->next = NULL;                                                       //【2】建立空的单链表
	std::cout<<"【NOTICE】InitList函数被执行,初始化一个空单链表成功!"<<std::endl;
}
/*************************************************************************************************************************
函数原型:
        LinkList CreatListHead(LinkList& pHead)
函数说明:
        【1】通常用一个【头指针】来标识一个单链表,如单链表L,头指针为"NULL"时,则表示一个空表。此外,为了操作上的方便,在单
		     链表第一个结点之前附加一个结点,称为【头结点】。
		【2】采用头插法建立单链表
		     该方法从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即
			 头结点之后。
		【3】采用头插法建立单链表,读入数据的顺序与生成的链表中元素的顺序是相反的。
**************************************************************************************************************************/
LinkList CreatListHead(LinkList& pHead)
{
	LNode* insertNode = NULL;
	int    insertData = 0;
	std::cout<<"【NOTICE】请输入单链表第一个要插入结点的数据insertData:";
	std::cout<<std::endl;
	std::cin>>insertData;                                              //【1】输入新结点数据域的值
	while(insertData!=9999)
	{
		insertNode = (LNode*)std::malloc(sizeof(LNode));              //【2】创建新结点
		insertNode->data = insertData;
		insertNode->next = pHead->next;
		pHead->next = insertNode;
		std::cout<<"【NOTICE】请输入下一个结点数据域的数据"<<std::endl;
		std::cin>>insertData;
	}//while
	return pHead;
}
/*************************************************************************************************************************
函数原型:
        LinkList CreatListTail(LinkList& pHead)
函数说明:
        【1】尾插法建立单链表。
		【2】该方法是将新结点插入到当前链表的表尾,为此,必须增加一个尾指针r,使其始终指向当前链表的尾结点。
**************************************************************************************************************************/
LinkList CreatListTail(LinkList& pHead)
{
	int      insertData  = 0;                                      //【1】设单链表元素的类型为整形
	LNode*   insertNode  = NULL;
	LNode*   pTail       = NULL;

	
	pTail = pHead;                                                  //【3】让表尾指针指向头结点
	
	std::cout<<"【NOTICE】请输入单链表第一个要插入结点的数据insertData"<<std::endl;
	std::cin>>insertData;                                           //【4】输入结点的值

	while(insertData!=9999)
	{
		insertNode = (LNode*)std::malloc(sizeof(LNode));
		insertNode->data = insertData;
		pTail->next = insertNode;
		pTail       = insertNode;
		std::cout<<"【NOTICE】请输入下一个结点数据域的数据"<<std::endl;
		std::cin>>insertData;
	}//while
	pTail->next = NULL;
	return pHead;
}
/*************************************************************************************************************************
函数原型:
        void PrintList(LinkList pHead)
函数说明:
        打印单链表,单链表的遍历
**************************************************************************************************************************/
void PrintList(LinkList pHead)
{
	LNode* pTemp = NULL;
	pTemp = pHead->next;

	if(pHead->next==NULL)
	{
		std::cout<<"【NOTICE】PrintList函数被执行,但是单链表为一个空链表!"<<std::endl;
	}
	else
	{
		std::cout<<"【NOTICE】单链表中存储的数据如下所示:"<<std::endl;
		while(pTemp)
		{
			std::cout<<pTemp->data<<std::endl;
			pTemp = pTemp->next;
		}
	}
}//void
/*************************************************************************************************************************
函数原型:
        void CleanList(LinkList pHead)
函数说明:
	    清除线性表中的所有元素,即释放单链表pHead中所有的结点,使之成为一个空表。
**************************************************************************************************************************/
void CleanList(LinkList& pHead)
{
	LNode* pNext = NULL;
	LNode* pTemp = NULL;
	pTemp = pHead->next;
	if(pHead->next==NULL)
	{
		std::cout<<"【NOTICE】CleanList函数执行,链表为空!"<<std::endl;
	}
	while (pTemp!=NULL)
	{
		pNext = pTemp->next;                     //【1】保存下一个结点的指针
		std::free(pTemp);
		pTemp = pNext;                           //【2】表头后移
	}
	std::cout<<"【NOTICE】CleanList函数执行完毕,链表已经清除!"<<std::endl;
	pHead->next = NULL;
}//void
/*************************************************************************************************************************
函数原型:
        int SizeList(LinkList pHead)
函数说明:
	    返回单链表的实际长度
**************************************************************************************************************************/
int SizeList(LinkList pHead)
{
	int    iSize = 0;
	LNode* pTemp = NULL;
	pTemp = pHead->next;
	while (pTemp!=NULL)
	{
		iSize++;
		pTemp = pTemp->next;
	}
	std::cout<<"【NOTICE】SizeList函数已经执行,链表的长度为 = "<<iSize<<std::endl;
	return iSize;
}
/*************************************************************************************************************************
函数原型:
       bool isEmptyList(LNode* pHead)
函数说明:
	    检查单链表是否为空,若为空,则返回1,否则返回0
**************************************************************************************************************************/
bool IsEmpty(LinkList pHead)
{
	LNode* pTemp = NULL;
	pTemp = pHead->next;

	if(pHead->next==NULL)
	{
		std::cout<<"【NOTICE】IsEmpty函数执行成功,链表为空!"<<std::endl;
		return true;
	}
	else
	{
		std::cout<<"【NOTICE】IsEmpty函数执行成功,链表非空!"<<std::endl;
		return false;
	}
}
/*************************************************************************************************************************
函数原型:
       LNode* GetElement(LinkList pHead,int i)
函数说明:
	    【1】按序号查找结点值
		【2】在单链表中从第一个结点出发,顺着指针域逐个往下搜索,直到找到第i个结点为止,否则返回最后一个结点指针域NULL
		【3】本算法取出单链表L(带头结点)中第i个位置的结点指针
**************************************************************************************************************************/
LNode* GetElement(LinkList pHead,int iPos)
{
	int    iCount = 0;
	LNode* pTemp  = NULL;
	pTemp = pHead->next;

	if(iPos<1)                                                                     //【1】位置合法性检查
	{
		std::cout<<"【NOTICE】GetElement函数执行成功,iPos位置非法!"<<std::endl;
		std::system("pause");
		std::exit(1);
	}
	if(pHead->next==NULL)                                                          //【2】单链表是否为空
	{
		std::cout<<"【NOTICE】GetElement函数执行成功,链表为空!"<<std::endl;
		std::system("pause");
		std::exit(1);
	}
	while (pTemp!=NULL)
	{
		++iCount;
		if(iCount==iPos)
		{
			break;
		}
		pTemp = pTemp->next;
	}
	if(iCount<iPos)
	{
		std::cout<<"【NOTICE】GetElement函数执行成功,iPos值超出链表长度!"<<std::endl;
		std::system("pause");
		std::exit(1);
	}
	return pTemp;
}
/*************************************************************************************************************************
函数原型:
       LNode* LocateElem(LinkList pHead,ElemType x)
函数说明:
	    【1】按值查找表结点
		【2】从单链表第一个结点开始,由前往后依次比较表中各结点数据域的值,,若某结点数据域的值相等,则返回该节点的指针。
		     若整个单链表中没有这样的结点,则返回NULL.
**************************************************************************************************************************/
LNode* LocateElem(LinkList pHead,ElemType x)
{
	LNode* pTemp = NULL;
	pTemp = pHead->next;

	if(pHead->next == NULL)
	{
		std::cout<<"【NOTICE】LocateElem函数执行完毕,链表为空!"<<std::endl;
		std::system("pause");
		return NULL;
	}
	while((pTemp->data!=x)&&(pTemp!=NULL))
	{
		pTemp = pTemp->next;
	}
	if((pTemp->data!=x)&&(pTemp->next==NULL))
	{
		std::cout<<"【NOTICE】LocateElem函数执行完毕,在链表中没有找到X值!!"<<std::endl;
		std::system("pause");
		std::exit(1);
	}
	return pTemp;
}
/*************************************************************************************************************************
函数原型:
       bool InsertList(LinkList& pHead,int i,ElemType x)
函数说明:
	    【1】插入结点操作
		【2】插入操作是将值为X的新结点插入到单链表pHead的第i个位置上。
		【3】插入操作的步骤:
		     (1)先检查插入位置的合法性
			 (2)找到待插入位置的前驱结点,即第i-1个结点
			 (3)再在其后插入位置的新结点。
**************************************************************************************************************************/
bool InsertList(LinkList& pHead,int iPos,ElemType x)
{
	if(iPos<1)
	{
		std::cout<<"【NOTICE】InsertList函数被执行,但是元素插入的位置不合法!"<<std::endl;
		std::system("pause");
		return false;
	}
	LNode*   pTemp       = NULL;
    LNode*   pInsertNode = NULL;

	pInsertNode = (LNode*)std::malloc(sizeof(LNode));
	pInsertNode->data = x;

	pTemp = GetElement(pHead,iPos-1);
	
	pInsertNode->next = pTemp->next;
	pTemp->next = pInsertNode;

	std::cout<<"【NOTICE】InsertList函数被执行,插入成功!"<<std::endl;
	return true;
}
/*************************************************************************************************************************
函数原型:
       bool DeleteList(LinkList& pHead,int iPos)
函数说明:
	    【1】删除结点操作
		【2】删除结点操作是将单链表pHead的第i个位置上的结点删除
		【3】删除操作的步骤:
		     (1)先检查删除位置的合法性
			 (2)然后查找表中第iPos-1个结点,即被删除结点的前驱结点
			 (3)再将其删除
**************************************************************************************************************************/
bool DeleteList(LinkList& pHead,int iPos)
{
	if(iPos<1)
	{
		std::cout<<"【NOTICE】DeleteList函数被执行,但是删除元素的位置不合法!"<<std::endl;
		std::system("pause");
		return false;
	}
	LNode* pTemp  = NULL;
	LNode* pDelete= NULL;
	pTemp  = GetElement(pHead,iPos-1);
	pDelete= GetElement(pHead,iPos);
	pTemp->next = pDelete->next;
	std::free(pDelete);
	std::cout<<"【NOTICE】DeleteList函数被执行,删除成功!"<<std::endl;
	return true;
}
int main()
{
	LinkList pHead   = NULL;
	LinkList pTail   = NULL;

	int      iLength = 0;
	ElemType posElem;

	InitList(pHead);
	PrintList(pHead);
	CreatListHead(pHead);
	PrintList(pHead);

	InitList(pTail);
	CreatListTail(pTail);
	PrintList(pTail);

	LNode* pValue = NULL;
	pValue = GetElement(pTail,2);
	std::cout<<"【NOTICE】单链表中的第二个元素的值 = "<<pValue->data<<std::endl;
	SizeList(pTail);

	bool flagEmpty = true;
	flagEmpty = IsEmpty(pTail);

	if(flagEmpty)
	{
		std::cout<<"【NOTICE】单链表为空表!"<<std::endl;
	}
	else
	{
		std::cout<<"【NOTICE】单链表不为空!"<<std::endl;
	}

	LNode* pData = NULL;
	pData = LocateElem(pTail,2);
	std::cout<<"【NOTICE】查找出来的值 = "<<pData->data<<std::endl;

	InsertList(pTail,2,8888);
	PrintList(pTail);


	CleanList(pTail);
	PrintList(pTail);
	SizeList(pTail);

	std::system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值