链表是一种物理存储单元上非连续、非顺序的数据结构。
一、链表的特点
(1)链表是由0或多个结点构成的
(2)除头结点外,每个结点都有一个前驱结点
(3)除尾结点外,每个结点都有一个后继结点
(4)链表的每个结点除了存储当前结点数据外,还存储下一个结点的地址
头结点:数据域无效
首结点:第一个数据域有效的结点
尾结点:指针域为空
空链表:既是头结点又是尾结点
三、链表的实现
1.定义数据元素的类型
typedef struct UsrInfo
{
int id;//编号
char name[20]; //名字
}data_t;
2.定义单链表中节点的结构体
typedef struct Node
{
data_t data;// 当前节点的数据元素
struct Node * pNext;//下一个节点的首地址
}Node;
3.定义描述一个单链表的结构体
typedef struct Link
{
Node * pHead;//单链表中第一个节点的首地址
int count;//节点的个数
}Link;
4.创建一个新节点
Node* createNode(data_t data)
{
Node* pNode =(Node*) malloc(sizeof(Node));
if(NULL == pNode)
{
return NULL;
}
memset(pNode,'\0',sizeof(Node));
pNode->data = data;
return pNode;
}
5.创建空链表,没有一个节点,pHead = NULL,count = 0返回值:空链表表结构的首地址
Link* createLink()
{
Link* pLink = (Link*)malloc(sizeof(Link));
if(NULL == pLink)
{
return NULL;
}
memset(pLink,'\0',sizeof(Link));
return pLink;
}
6.头插法,只要插入一个元素pHead就要被更新
int pushItemFront(Link* pLink,data_t data)
{
if(NULL == pLink)
{
return LINK_ERROR;
}
//创建一个新节点
Node* pNode = createNode(data);
//将新节点插入到链表中
pNode->pNext = pLink->pHead;
pLink->pHead = pNode;
pLink->count++;
return LINK_OK;
}
7.显示
void showLink(Link * pLink)
{
if(NULL == pLink)
{
return;
}
Node * pTmp = pLink->pHead;
while(pTmp != NULL)
{
printf("id = %d name = %s\n",pTmp->data.id,pTmp->data.name);
pTmp = pTmp->pNext;
}
}
8.中间插入,在指定的位置插入元素,位置的编号从0开始,要插入的节点必须要找到要插入位置的前一个节点。
int insertItemLink(Link *pLink,int ioffset,data_t data)
{
if(NULL == pLink||ioffset < 0||ioffset > pLink->count)
{
return LINK_ERROR;
}
//创建一个新节点
Node* pNode = createNode(data);
//找到要插入位置的前一个节点,用pTmp表示
Node * pTmp = pLink->pHead;
int i;
for(i = 0;i<ioffset-1;i++)
{
pTmp = pTmp->pNext;
}
//头插
if(0 == ioffset)
{
pushItemFront(pLink,data);
return LINK_OK;
}
//插入
pNode->pNext = pTmp->pNext;
pTmp->pNext = pNode;
pLink->count++;
return LINK_OK;
}
9.销毁链表
void destroyLink(Link ** ppLink)
{
if(NULL == ppLink ||NULL == *ppLink)
{
return;
}
Node * pDel = (*ppLink)->pHead;
//释放一个一个节点
while(pDel != NULL)
{
(*ppLink)->pHead = pDel->pNext;
free(pDel);
pDel = (*ppLink)->pHead;
}
//释放表的结构体
free(*ppLink);
*ppLink = NULL;
}
10.删除指定位置元素,位置从0开始
int deleteItemLink(Link* pLink,int ioffset,data_t *pData)
{
if(NULL == pLink||ioffset < 0||ioffset > pLink->count)
{
return LINK_ERROR;
}
//pTmp是要删除的节点前一个节点
Node* pTmp = pLink->pHead;
int i;
for(i = 0;i < ioffset-1; i++)
{
pTmp = pTmp-> pNext;
}
//pDel删除的节点
Node* pDel = pTmp->pNext;
if(NULL != pData)
{
*pData = pDel->data;
}
pTmp->pNext = pDel->pNext;
free(pDel);
pDel = NULL;
pLink->count--;
return LINK_OK;
}
11.按照id查找名字,如果没有找到,就返回NOT_FOUND
int findItemLink(Link* pLink,data_t* pData)
{
if(NULL == pLink ||NULL == pData)
{
return LINK_ERROR;
}
//遍历链表,根据传进来的id一个一个去比较
//如果相等了,就将name带出来
Node* pTmp = pLink->pHead;
while(pTmp != NULL)
{
if(pTmp->data.id == pData->id)
{
strcpy(pData->name,pTmp->data.name);
return LINK_OK;
}
pTmp = pTmp->pNext;
}
return NOT_FOUND;
}