链表是数据结构中比较重要的一种,链表是一种数据存储结构,它有单项链表和双向链表以及复杂链表三种形式。
链表是一种动态数据结构,创建时不需指定它的长度,当插入新节点是我们只需要给新节点分配内存,然后调整指针的指向来保证新节点存在于链表中。
由于没有闲置的内存,链表的控件效率比数组要高。
其中单项链表包括两部分内容,指向下一个节点的指针和该节点的值。
指针中存放的是下一个节点的首地址,
下面是是一个单向链表的节点的定义。
struct ListNode
{
int m_pValue;
ListNode* m_pNext;
}
那么往这个链表中的末尾插入一个节点的操作就是。
//在链表的末尾添加元素
void AddToTail(ListNode** pHead,int value)
{
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;
}
}
在上面的代码中我们要特别注意函数的第一个参数pHead,它是一个指向指针的指针,
当我们往一个空链表中插入一个新节点时需要改变头指针。因此需要把pHead参数设置为指向指针的指针。
否则出了这个函数以后pHead仍然是一个空指针。
链表的查询操作需要的时间花费是O(n),而数组的查询操作所花费的时间却是O(1),由此看来链表在时间效率上要比数组低。
下面是关于链表的其他几种操作
//删除链表中的节点
Void RemoveNode(ListNode** pHead,int value)
{
If(pHead==NULL||*pHead==NULL)
Return;
ListNode* pDeletedNode=NULL;
If((*pHead)->m_nValue==value)
{
pDeletedNode=*pHead;
*pHead=(*pHead)->m_pNext;
}
Else
{
ListNode* pNode=*pHead;
While(pNode->m_pNext!=NULL && pNode->m_pNext->m_nValue!=value)
pNode = pNode->m_pNext;
if(pNode->m_pNext!=NULL && pNode->m_pNext->m_nValue==value)
{
pDeletedNode=pNode->m_pNext;
pNode-> m_pNext= pNode-> m_pNext-> m_pNext;
}
}
}
//使用栈反向输出链表中的数据
Void PrintListReversingly_Iteratively(ListNode* pHead)
{
Std::stack<ListNode*>nodes;
ListNode* pNode=pHead;
While(pNode!=NULL)
{
nodes.push(pNode);
pNode=pNode->m_pNext;
}
While(!nodes.Empty())
{
pNode=nodes.top();
printf(“%d\t”,pNode->m_nValue);
nodes.pop();;
}
}
//使用递归反向输出链表中的数据
Void PrintListReservingly_Recursively(ListNode* pHead)
{
If(pHead!=NULL)
{
If(pHead->m_pNext!=NULL)
{
PrintListReservingly_Recursively(pHead->m_pNext);
}
Printf(“%d\t”,pHead->m_nValue);
}
}