数据结构之链表
2016-02-22 08:39
225 查看
链表是数据结构中比较重要的一种,链表是一种数据存储结构,它有单项链表和双向链表以及复杂链表三种形式。
链表是一种动态数据结构,创建时不需指定它的长度,当插入新节点是我们只需要给新节点分配内存,然后调整指针的指向来保证新节点存在于链表中。
由于没有闲置的内存,链表的控件效率比数组要高。
其中单项链表包括两部分内容,指向下一个节点的指针和该节点的值。
指针中存放的是下一个节点的首地址,
下面是是一个单向链表的节点的定义。
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);
}
}
链表是一种动态数据结构,创建时不需指定它的长度,当插入新节点是我们只需要给新节点分配内存,然后调整指针的指向来保证新节点存在于链表中。
由于没有闲置的内存,链表的控件效率比数组要高。
其中单项链表包括两部分内容,指向下一个节点的指针和该节点的值。
指针中存放的是下一个节点的首地址,
下面是是一个单向链表的节点的定义。
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);
}
}
相关文章推荐
- mybatis核心数据结构详解——ResultMap和ResultMapping
- 数据结构之消息队列
- 数据结构(八)
- 数据结构(七)
- 数据结构(六)
- 数据结构(五)
- 数据结构(四)
- 数据结构(三)
- 数据结构(二)
- 数据结构(一)
- hdu 3577(线段树区间更新)
- 数据结构: 数组与字符串问题
- 跟我学数据结构之树
- 跟我学数据结构之数组和广义表
- 《数据结构与算法分析(c描述)》——二叉搜索树实现
- 树和递归(一)[leetcode]Balanced Binary Tree
- opencv基本数据结构
- 数据结构(9)--链队列的定义以及相关操作的实现
- 数据结构(8)--栈的应用之行编辑程序、括号匹配检验、数制转换、hanio塔问题
- 最小生成树-普里姆方法(Prim)