您的位置:首页 > 其它

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

2017-08-25 16:26 483 查看
/************************************************************************************************************************
文件说明:
线性表的链式存储之【单链表】、【双链表】、【循环链表】、【静态链表】
详细说明:
【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;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: