C++相关
链表
含义: 一个数据所在的内存块被分为两个部分,第一个部分放数据,而第二个部分则放下一个数据的地址,以此来连接各个数据,最后一个内存块放的地址为NULL。这样形成的一个有关联的表就是链表。
在代码中,链表的一个节点是这样的:
struct SNode
{
SNode()
{
nID = 0;
pNextNode = nullptr;
}
//数据部分
int nID;
//指针:指向下一个节点,下一个节点:SNode类型,指针类型SNode*
SNode* pNextNode;
};
创建操作:
void createList(SNode* pHead,int nSize);
int main()
{
//链表首先需要有个头。
SNode* pHead = new SNode();
//存储数据。
cin >>pHead->nID;
createList(pHead, 3);
}
void createList(SNode* pHead, int nSize)
{
//指向链表的最后一个结点
SNode* pLastNode = pHead;
for (int i = 0; i < nSize; i++)
{
//创建新的节点
SNode* pNewNode = new SNode();
//存储数据。
cin >> pNewNode->nID;
//让最后一个结点跟新结点连接:
//最后一个结点的下一个结点指针存储当前新结点的内存地址。
pLastNode->pNextNode = pNewNode;
//链表变了,多了一个结点,最后一个结点要修改,刚刚的新节点就变成了链表的最后一个节点。
pLastNode = pNewNode;
}
遍历操作:
void viewList(SNode* pHead);
int main()
{
//链表首先需要有个头。
SNode* pHead = new SNode();
//存储数据。
cin >>pHead->nID;
createList(pHead, 3);
viewList(pHead);
}
void viewList(SNode* pHead)
{
//定义一个临时指针 存储当前找到的节点的内存地址
//一开始,当前找到的一定是头
SNode* pCurNode = pHead;
//每找到一个结点获取对应数据后,当前节点应该改变指向,指向当前节点的下一个结点。
//最终这个当前节点指针一定会存储空。
//循环,如果当前节点指针存储的内存地址不是空,就可以处理数据
while (pCurNode)
{
//当前节点已经获取到了,获取数据
cout << pCurNode->nID<<endl;
//更改当前节点指针指向当前节点的下一个节点。
pCurNode = pCurNode->pNextNode;
}
}
查找操作:
//查找:头,查找的位置,(0表示头的位置,依次往下)
SNode* findNode(SNode* pHead, int nPosition);
int main()
{
//链表首先需要有个头。
SNode* pHead = new SNode();
//存储数据。
cin >>pHead->nID;
createList(pHead, 3);
int nPosition = 0;
cin >> nPosition;
SNode* pFindNode = findNode(pHead, nPosition);
//找到了对应节点,使用它,使用的要注意。
//判空
if (pFindNode)
{
cout << "找到的节点是:" << pFindNode->nID << endl;
}
else
{
cout << "查找位置有误" << endl;
}
}
SNode* findNode(SNode* pHead, int nPosition)
{
//定义一个变量,表示当前遍历到的节点在链表是第几个,头是第0个
int nIndex = 0;
//遍历。
SNode* pCurNode = pHead;
while (pCurNode)
{
//nIndex:当前找到的是第几个。
if (nIndex == nPosition)//遍历数到的个数跟传递进来的位置值一样,意味着当前遍历到的这个是要查找的节点。
{
return pCurNode;
}
pCurNode = pCurNode->pNextNode;
//下一个
nIndex++;
}
//如果链表遍历完,都没有找到,那么返回空的指针。
return nullptr;
}
插入操作:
//插入:链表,插入的节点,位置,
SNode* insertNode(SNode* pHead, SNode* pInsertNode, int nPosition);
int main()
{
//链表首先需要有个头。
SNode* pHead = new SNode();
//存储数据。
cin >>pHead->nID;
createList(pHead, 3);
int nPosition = 0;
cin >> nPosition;
SNode* pInstertNode = new SNode();
cin >> pInstertNode->nID;
pHead = insertNode(pHead, pInstertNode, nPosition);
cout << "插入后的链表" << endl;
viewList(pHead);
}
SNode* insertNode(SNode* pHead, SNode* pInsertNode, int nPosition)
{
//如果插入的位置是第0个。
//那么插入的节点应该变成新的头节点,
if (0 == nPosition)
{
//先把插入的节点跟头连接起来, 把头的地址存储到插入结点的下一个结点指针。
pInsertNode->pNextNode = pHead;
//插入的节点变成新的头节点
pHead = pInsertNode;
return pHead;
}
//如果插入不是在0的位置。
//查找结点,查找哪个结点? 查找要插入的位置的前一个节点。
//插入的节点跟找到的节点的下一个结点连接起来, 插入结点的下一个结点指针存储找到的节点的下一个结点指针里面的地址。
//找到结点的下一个结点指针存储插入的节点的地址。
int nIndex = 0;
SNode* pCurNode = pHead;
while (pCurNode)
{
//这个索引如果等于插入位置-1,意味着到了插入位置的前一个节点是pCurNode
if (nIndex == nPosition - 1)
{
// 插入结点的下一个结点指针存储找到的节点的下一个结点指针里面的地址。
pInsertNode->pNextNode = pCurNode->pNextNode;
//找到结点的下一个结点指针存储插入的节点的地址。
pCurNode->pNextNode = pInsertNode;
break;
}
pCurNode = pCurNode->pNextNode;
nIndex++;
}
if (nIndex <= nPosition)
{
cout << "插入位置有误" << endl;
}
return pHead;
}
删除操作:
//删除:链表,删除的位置,默认值:真,表示删除的时候删除节点会被释放。
SNode* deleteNode(SNode*& pHead, int nPosition, bool bDelete = true);
int main()
{
//链表首先需要有个头。
SNode* pHead = new SNode();
//存储数据。
cin >>pHead->nID;
createList(pHead, 3);
int nPosition = 0;
cin >> nPosition;
if (pHead)
{
SNode* pDeleteNode = deleteNode(pHead, nPosition, false);
if (pDeleteNode)
{
cout << "被删除的节点是:" << pDeleteNode->nID << endl;
}
//用完后删掉。
if (pDeleteNode)
{
delete pDeleteNode;
pDeleteNode = nullptr;
}
cout << "删除节点后" << endl;
viewList(pHead);
}
}
SNode* deleteNode(SNode*& pHead, int nPosition, bool bDelete /*=true*/)
{
if (!pHead)
{
cout << "链表不存在" << endl;
return nullptr;
}
//删除的是头的位置,那么头下面的那一个节点应该变成新的头。
SNode* pDeleteNode = nullptr;
if (0 == nPosition)
{
//不要直接把头改掉。
//首先先把头节点接收起来
pDeleteNode = pHead;
//更改头。
pHead = pHead->pNextNode;
if (bDelete)
{
if (pDeleteNode)
{
delete pDeleteNode;
pDeleteNode = nullptr;
}
}
else
{
//pDeleteNode的下一个结点指针还是连着头的下一个结点,让他指向空。
pDeleteNode->pNextNode = nullptr;
}
return pDeleteNode;
}
//删除的位置非0.
//找要删除位置的前一个节点。
int nIndex = 0;
SNode* pCurNode = pHead;
while (pCurNode&& pCurNode->pNextNode)
{
//这个索引如果等于删除位置-1,意味着到了删除位置的前一个节点是pCurNode
if (nIndex == nPosition - 1)
{
//把删除的节点接收起来。
pDeleteNode = pCurNode->pNextNode;
//被删除的节点跟他得 前一个节点断开, 找到结点的下一个节点指针存储删除节点的下一个节点指针
pCurNode->pNextNode = pDeleteNode->pNextNode;
break;
}
pCurNode = pCurNode->pNextNode;
nIndex++;
}
//如果循环结束后,pDeleteNode还是nullptr,意味着找要删除的节点还是找不到。
if (!pDeleteNode)
{
cout << "删除的位置有误" << endl;
return nullptr;
}
if (bDelete)
{
if (pDeleteNode)
{
delete pDeleteNode;
pDeleteNode = nullptr;
}
}
else
{
if (pDeleteNode)
{
//pDeleteNode的下一个结点指针还是连着头的下一个结点,让他指向空。
pDeleteNode->pNextNode = nullptr;
}
}
return pDeleteNode;
}
翻转操作:
SNode* reverseList(SNode* pHead);
int main()
{
//链表首先需要有个头。
SNode* pHead = new SNode();
//存储数据。
cin >>pHead->nID;
createList(pHead, 3);
pHead = reverseList(pHead);
cout << "逆序后的链表" << endl;
viewList(pHead);
}
SNode* reverseList(SNode* pHead)
{
//剩余链表指针,一开始是整条链表
SNode* pResidueList = pHead;
//前置结点指针,逆序后的链表。 一开始不存在,所以是空。
SNode* pPreList = nullptr;
//专门用于遍历查找的节点当前节点,一开始是头节点 剩余链表的头。
SNode* pCurNode = pHead;
while (pCurNode)//如果剩余链表的头为空,原链表没了,新的就完成了。
{
//接收去掉当前节点后的剩余链表
pResidueList = pCurNode->pNextNode;
//断开当前节点跟原链表节点的连接,逆向指向。
pCurNode->pNextNode = pPreList;
//新的链表存储。 存储原来的头。
pPreList = pCurNode;
//遍历存储。 查找剩余链表的头。
pCurNode = pResidueList;
}
return pPreList;
}