18从汇编的角度深入理解c++_深入理解链表(自己编写代码实现链表)
#define SUCCESS 1 //执行成功
#define ERROR -1 //执行失败
#define INDEX_ERROR -2 //索引号错误
#define BUFFER_EMPTY -3 //缓冲区为空
template<class LK_ELE>
class LinkNode{
public:
LinkNode();
~LinkNode();
public:
bool IsEmpty(); //判断是否为空
void Clear(); //清空链表
int GetElement(int index,LK_ELE& Element); //获取索引index中存的元素
int GetElement(LK_ELE& Element); //根据元素获取索引值
int Insert(LK_ELE Element); //新增元素
int Insert(int index,LK_ELE& Element);//插入元素
int Delete(int index); //删除指定元素
int GetSize(); //获取链表中元素个数
private:
typedef struct _NODE{
LK_ELE data;
_NODE* lpNext;
}NODE,*PNODE;
PNODE GetIndexCurrentNode(int dwIndex); //获取索引的指针
PNODE GetIndexPreviousNode(int dwIndex);//获取索引前一个节点的指针
PNODE GetIndexNextNode(int dwIndex); //获取索引后一个节点的指针
private:
PNODE m_List; //链表头指针
int m_length; //链表元素个数
};
template<class LK_ELE>
LinkNode<LK_ELE>::LinkNode():m_List(NULL),m_length(0){
};
template<class LK_ELE>
LinkNode<LK_ELE>::~LinkNode(){
Clear();
};
template<class LK_ELE>
bool LinkNode<LK_ELE>::IsEmpty(){
if(m_List==NULL || m_length==0)
return 1;
else
return 0;
};
template<class LK_ELE>
void LinkNode<LK_ELE>::Clear(){
//1、判断链表是否为空
if(m_List==NULL || m_length==0)
return;
//2、循环删除链表
PNODE p1 = m_List;
while(p1->lpNext)
{
PNODE pTemp = p1;
p1 = p1->lpNext;
delete pTemp;
}
//3、删除最后1个节点
delete p1;
//m_List = NULL;
m_length = 0;
};
template<class LK_ELE>
int LinkNode<LK_ELE>::GetElement(int index,LK_ELE& Element){
//1、判断索引是否有效
if(index<0 || index>=m_length)
{
return INDEX_ERROR;
}
//2、取得索引指向的结点
PNODE p1 = m_List;
for(int i=0;i<index;i++)
{
p1 = p1->lpNext;
}
memcpy(&Element,&p1->Data,sizeof(LK_ELE));
return SUCCESS;
};
template<class LK_ELE>
int LinkNode<LK_ELE>::GetElement(LK_ELE& Element){
//1、判断链表是否为空
if(m_List==NULL || m_length==0)
return 0;
//2、循环遍历链表
PNODE p1 = m_List;
for(int i=0;i<=m_length;i++)
{
if(!memcmp(&Element,&p1->Data,sizeof(LK_ELE)))
{
return i;
}
p1 = p1->lpNext;
}
return 0;
};
template<class LK_ELE>
int LinkNode<LK_ELE>::Insert(LK_ELE Element){
PNODE pNewNode = new NODE;
memset(pNewNode,0,sizeof(NODE));
memcpy(pNewNode->Data,&Element,sizeof(LK_ELE));
//1、判断链表是否为空
if(m_List==NULL || m_length==0)
{
m_List = pNewNode;
m_length++;
return SUCCESS;
}
//否则,遍历到链表末尾
PNODE p1 = m_List;
for(int i=0;i<m_length-1;i++)
{
p1 = p1->lpNext;
}
p1->lpNext = pNewNode;
m_length++;
return SUCCESS;
};
template<class LK_ELE>
PNODE LinkNode<LK_ELE>::GetIndexCurrentNode(int dwIndex){
};
template<class LK_ELE>
PNODE LinkNode<LK_ELE>::GetIndexPreviousNode(int dwIndex){
};
template<class LK_ELE>
PNODE LinkNode<LK_ELE>::GetIndexNextNode(int dwIndex){
};
template<class LK_ELE>
int LinkNode<LK_ELE>::Insert(int dwIndex,LK_ELE Element){
PNODE pPreNode = NULL;
PNODE pCurrNode = NULL;
PNODE pNextNode = NULL;
PNODE pNewNode = new NODE;
memset(pNewNode,0,sizeof(NODE));
memcpy(pNewNode,&Element,sizeof(LK_ELE));
//1、判断索引是否有效
if(dwIndex < 0 || dwIndex > m_length)
{
return INDEX_ERROR;
}
//2、判断链表是否为空
if(m_List==NULL || m_length==0)
{
if(dwIndex==0)
{
m_List = pNewNode;
m_length++;
return SUCCESS;
}
return INDEX_ERROR;
}
//3、链表不为空且索引值为0
if(dwIndex==0)
{
pNewNode->lpNext = m_List;
m_List = pNewNode;
m_length++;
return SUCCESS;
}
//4、链表不为空且索引值为链表尾
if(dwIndex==m_length)
{
pPreNode = GetIndexPreviousNode(index);
pPreNode->lpNext = pNewNode;
m_length++;
return SUCCESS;
}
//4、链表不为空且索引值为链表中间
pPreNode = GetIndexPreviousNode(dwIndex);
pCurrNode = GetIndexCurrentNode(dwIndex);
pPreNode->lpNext = pNewNode;
pNewNode->lpNext = pCurrNode;
m_length++;
return SUCCESS;
};
template<class LK_ELE>
int LinkNode<LK_ELE>::Delete(int index){
PNODE pPreNode = NULL;
PNODE pNextNode = NULL;
//1、判断是否为空
if(m_List==NULL || m_length==0)
{
return BUFFER_EMPTY;
}
//2、判断索引是否有效
if(dwIndex < 0 || dwIndex >= m_length)
{
return INDEX_ERROR;
}
//3、如果链表中只有头节表,且要删除头结点
if(m_length==1 && dwIndex==0)
{
delete m_List;
m_List = NULL;
m_length--;
return SUCCESS;
}
//4、如果要删除头结点
if(dwIndex==0)
{
pNextNode = GetIndexNextNode(dwIndex);
delete m_List;
m_List = pNextNode;
m_length--;
return SUCCESS;
}
//5、其他情况
pPreNode = GetIndexPreviousNode(dwIndex);
pNextNode = GetIndexNextNode(dwIndex);
delete pPreNode->lpNext;
pPreNode->lpNext = pNewNode;
m_length--;
return SUCCESS;
};
template<class LK_ELE>
int LinkNode<LK_ELE>::GetSize(){
return m_length;
};
这段代码有个致命的问题,我找了2天才知道。
error C2143: 语法错误 : 缺少“;”(在“LinkedList<T_ELE>::GetIndexPreviousNode”的前面)
出现这种问题的原因是:模板类中嵌套使用模板中的元素。
我们首先应该改为:
template<class T_ELE>
LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexPreviousNode(DWORD dwIndex)
{
PNODE pTempNode = NULL;
// 就是一个循环
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
return BUFFER_IS_EMPTY;
}
// 2. 判断索引值是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
return INDEX_IS_ERROR;
}
pTempNode = m_pList;
for (DWORD i = 0; i < dwIndex - 1; i++)
{
pTempNode = pTempNode->pNext;
}
return pTempNode;
}
但是编译器还是报错:
warning C4346: “LinkedList<T_ELE>::PNODE”: 依赖名称不是类型 1> 用“typename”为前缀来表示类型 1>error C2143: 语法错误 : 缺少“;”(在“LinkedList<T_ELE>::GetIndexPreviousNode”的前面)
PNODE,我们程序员在这个时候把PNODE当做类型,作为函数的返回值。
但是编译器不知道啊,编译器这个时候还以为是LinkedList<T_ELE>中的成员变量呢。
解决办法:
方法1、使用关键字typename,明确告诉编译器PNODE,就是1个类型,
template<class T_ELE>
typename LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexPreviousNode(DWORD dwIndex)
{
PNODE pTempNode = NULL;
// 就是一个循环
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
return BUFFER_IS_EMPTY;
}
// 2. 判断索引值是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
return INDEX_IS_ERROR;
}
pTempNode = m_pList;
for (DWORD i = 0; i < dwIndex - 1; i++)
{
pTempNode = pTempNode->pNext;
}
return pTempNode;
}
2、将函数定义移到类内,定义的时候,直接实现。
PNODE GetIndexCurrentNode(DWORD dwIndex); //获取索引为dwIndex的指针
PNODE GetIndexPreviousNode(DWORD dwIndex){
PNODE pTempNode = NULL;
// 就是一个循环
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
return BUFFER_IS_EMPTY;
}
// 2. 判断索引值是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
return INDEX_IS_ERROR;
}
pTempNode = m_pList;
for (DWORD i = 0; i < dwIndex - 1; i++)
{
pTempNode = pTempNode->pNext;
}
return pTempNode;
}; //获取索引为dwIndex的前一个节点指针
PNODE GetIndexNextNode(DWORD dwIndex); //获取索引为dwIndex的后一个节点指针
private:
PNODE m_pList; //链表头指针,指向第一个节点
DWORD m_dwLength; //元素的数量
};
3、将嵌套类移到类外
但是这种方法,直到c++11才支持,并且还得用关键字using
template <class T_ELE> usingPNODE=_NODE<T_ELE>* ;
现将2份完整的代码头文件和源码文件如下:
//LinNode.h文件
#include<Windows.h>
#define SUCCESS 1 // 执行成功
#define ERROR -1 // 执行失败
#define INDEX_IS_ERROR -2 // 错误的索引号
#define BUFFER_IS_EMPTY -3 // 缓冲区已空
template <class T_ELE>
class LinkedList
{
public:
LinkedList();
~LinkedList();
public:
BOOL IsEmpty(); //判断链表是否为空 空返回1 非空返回0
void Clear(); //清空链表
DWORD GetElement(IN DWORD dwIndex, OUT T_ELE& Element); //根据索引获取元素
DWORD GetElementIndex(IN T_ELE& Element); //根据元素获取链表中的索引
DWORD Insert(IN T_ELE Element); //新增元素
DWORD Insert(IN DWORD dwIndex, IN T_ELE Element); //根据索引新增元素
DWORD Delete(IN DWORD dwIndex); //根据索引删除元素
DWORD GetSize(); //获取链表中元素的数量
void Traverse(); //遍历链表中的元素
public:
typedef struct _NODE
{
T_ELE Data;
_NODE *pNext;
}NODE,*PNODE;
PNODE GetIndexCurrentNode(DWORD dwIndex); //获取索引为dwIndex的指针
PNODE GetIndexPreviousNode(DWORD dwIndex); //获取索引为dwIndex的前一个节点指针
PNODE GetIndexNextNode(DWORD dwIndex); //获取索引为dwIndex的后一个节点指针
private:
PNODE m_pList; //链表头指针,指向第一个节点
DWORD m_dwLength; //元素的数量
};
//无参构造函数 初始化成员
template<class T_ELE> LinkedList<T_ELE>::LinkedList()
:m_pList(NULL), m_dwLength(0)
{
}
//析构函数 清空元素
template<class T_ELE> LinkedList<T_ELE>::~LinkedList()
{
Clear();
}
//判断链表是否为空
template<class T_ELE> BOOL LinkedList<T_ELE>::IsEmpty()
{
if (m_pList == NULL || m_dwLength == 0)
{
return true;
}
printf("非空\n");
return false;
}
//清空链表
template<class T_ELE> void LinkedList<T_ELE>::Clear()
{
PNODE pTempNode = m_pList;
PNODE pDeleteNode = NULL;
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
return BUFFER_IS_EMPTY;
}
// 2. 循环删除链表中的节点
for (DWORD i = 0; i < m_dwLength; i++)
{
pDeleteNode = pTempNode;
pTempNode = pTempNode->pNext;
delete pDeleteNode;
}
// 3. 删除最后一个节点并将链表长度置为0
m_dwLength = 0;
}
//根据索引获取元素
template<class T_ELE> DWORD LinkedList<T_ELE>::GetElement(IN DWORD dwIndex, OUT T_ELE& Element)
{
PNODE pTempNode =m_pList;
// 1. 判断索引是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
return INDEX_IS_ERROR;
}
// 2. 取得索引指向的节点
for (DWORD i = 0; i < dwIndex; i++)
{
pTempNode = pTempNode->pNext;
}
// 3. 将索引指向节点的值复制到OUT参数
//Element = pTempNode;
memcpy(&Element,pTempNode,sizeof(T_ELE));
return SUCCESS;
}
//根据元素内容获取索引
template<class T_ELE> DWORD LinkedList<T_ELE>::GetElementIndex(IN T_ELE& Element)
{
PNODE pTempNode = m_pList;
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
return BUFFER_IS_EMPTY;
}
// 2. 循环遍历链表,找到与Element相同的元素
for (DWORD i = 0; i < m_dwLength; i++)
{
if (memcmp(pTempNode, &Element, sizeof(T_ELE)) == 0)
{
return i;
}
pTempNode = pTempNode->pNext;
}
return ERROR;
}
//在链表尾部新增节点
template<class T_ELE> DWORD LinkedList<T_ELE>::Insert(IN T_ELE Element)
{
PNODE pNewNode = new NODE;
memset(pNewNode, 0, sizeof(NODE));
memcpy(&pNewNode->Data, &Element, sizeof(T_ELE));
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
m_pList = pNewNode;
m_dwLength++;
return SUCCESS;
}
// 2. 如果链表中已经有元素
PNODE pTempNode = m_pList;
for (DWORD i = 0; i < m_dwLength-1; i++)
{
pTempNode = pTempNode->pNext;
}
pTempNode->pNext = pNewNode;
m_dwLength++;
return SUCCESS;
}
//将节点新增到指定索引的位置 0 1 2 3 4
template<class T_ELE> DWORD LinkedList<T_ELE>::Insert(IN DWORD dwIndex, IN T_ELE Element)
{
PNODE pPreviousNode = NULL;
PNODE pCurrentNode = NULL;
PNODE pNewNode = new NODE;
memset(pNewNode, 0, sizeof(T_ELE));
memcpy(&pNewNode->Data, &Element, sizeof(T_ELE));
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
if (dwIndex == 0)
{
m_pList = pNewNode;
m_dwLength++;
return SUCCESS;
}
return INDEX_IS_ERROR;
}
// 2. 判断索引值是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
return INDEX_IS_ERROR;
}
// 3. 如果索引为0
if (dwIndex == 0)
{
pNewNode->pNext = m_pList;
m_pList = pNewNode;
m_dwLength++;
return SUCCESS;
}
// 4. 如果索引为链表尾
if (dwIndex == m_dwLength)
{
pPreviousNode = GetIndexPreviousNode(dwIndex);
pPreviousNode->pNext = pNewNode;
m_dwLength++;
return SUCCESS;
}
// 5. 如果索引为链表中
pPreviousNode = GetIndexPreviousNode(dwIndex);
pCurrentNode = GetIndexCurrentNode(dwIndex);
pPreviousNode->pNext = pNewNode;
pNewNode->pNext = pCurrentNode;
m_dwLength++;
return SUCCESS;
}
//根据索引删除节点
template<class T_ELE> DWORD LinkedList<T_ELE>::Delete(IN DWORD dwIndex)
{
PNODE pPreviousNode = NULL;
PNODE pNextNode = NULL;
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
return BUFFER_IS_EMPTY;
}
// 2. 判断索引值是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
return INDEX_IS_ERROR;
}
// 3. 如果链表中只有头节点,且要删除头节点
if (m_dwLength == 1 && dwIndex == 0)
{
delete m_pList;
m_pList = NULL;
m_dwLength--;
return SUCCESS;
}
// 4. 如果要删除头节点
if (dwIndex == 0)
{
pNextNode = GetIndexNextNode(dwIndex);
delete m_pList;
m_pList = pNextNode;
m_dwLength--;
return SUCCESS;
}
// 5. 如果是其他情况
pPreviousNode = GetIndexPreviousNode(dwIndex);
pNextNode = GetIndexNextNode(dwIndex);
delete pPreviousNode->pNext;
pPreviousNode->pNext = pNextNode;
m_dwLength--;
return SUCCESS;
}
//获取链表中节点的数量
template<class T_ELE> DWORD LinkedList<T_ELE>::GetSize()
{
DWORD NumbNode = 1;
PNODE pTempNode = m_pList;
while (pTempNode->pNext!=NULL)
{
NumbNode++;
pTempNode = pTempNode->pNext;
}
return NumbNode;
}
//获取dwIndex前面节点的地址
template<class T_ELE>
typename LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexPreviousNode(DWORD dwIndex)
{
PNODE pTempNode = NULL;
// 就是一个循环
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
printf("ERROR:链表为空\n");
return NULL;
}
// 2. 判断索引值是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
printf("ERROR:索引错误\n");
return NULL;
}
pTempNode = m_pList;
for (DWORD i = 0; i < dwIndex - 1; i++)
{
pTempNode = pTempNode->pNext;
}
return pTempNode;
}
//获取dwIndex节点的地址
template<class T_ELE>
typename LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexCurrentNode(DWORD dwIndex)
{
PNODE pTempNode = NULL;
// 就是一个循环
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
printf("ERROR:链表为空\n");
return NULL;
}
// 2. 判断索引值是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
printf("ERROR:索引错误\n");
return NULL;
}
pTempNode = m_pList;
for (DWORD i = 0; i < dwIndex ; i++)
{
pTempNode = pTempNode->pNext;
}
return pTempNode;
}
//获取dwIndex后面节点的地址
template<class T_ELE>
typename LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexNextNode(DWORD dwIndex)
{
PNODE pTempNode = NULL;
// 就是一个循环
// 1. 判断链表是否为空
if (m_pList == NULL || m_dwLength == 0)
{
printf("ERROR:链表为空\n");
return NULL;
}
// 2. 判断索引值是否有效
if (dwIndex<0 || dwIndex>m_dwLength)
{
printf("ERROR:索引错误\n");
return NULL;
}
pTempNode = m_pList;
for (DWORD i = 0; i < dwIndex + 1; i++)
{
pTempNode = pTempNode->pNext;
}
return pTempNode;
};
template<class T_ELE>
void LinkedList<T_ELE>::Traverse(){
PNODE current = m_pList; // 从链表头部开始遍历
while(current != NULL) // 当当前节点不为空时
{
// 访问当前节点的数据
// 这里假设 Data 是 T_ELE 类型的对象,你可以根据实际需要处理
T_ELE data = current->Data;
// 在这里进行你需要的操作,例如输出 data
// ...
printf("%d ",data);
current = current->pNext; // 移动到下一个节点
}
printf("\n******************\n");
}
//加1个获取根节点的代码实现
template<class T_ELE>
typename LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetRoot(){
return m_pList;
}
和测试的源码文件
#include "stdafx.h"
#include "MyLinkNode.h"
class Monster{
private:
int id;
int level;
char name[10];
public:
Monster(int ID,int LEVEL,char Name[]){
this->id = ID;
this->level = LEVEL;
memcpy(name,Name,strlen(Name)+1);
};
Monster(){};
~Monster(){
};
};
int _tmain(int argc, _TCHAR* argv[])
{
Monster n1(1,1,"刺猬");
Monster n2(2,2,"土狼");
Monster n3(3,3,"海盗鼠");
Monster n4(4,4,"侠客虎王");
Monster n5(5,5,"翻身猴");
Monster n6(6,6,"七彩蛇");
Monster n7(7,7,"黑野猪");
LinkedList<Monster>* p1 = new LinkedList<Monster> ;
p1->Insert(n1);
p1->Insert(n2);
p1->Insert(n3);
p1->Insert(n4);
p1->Insert(n5);
p1->Insert(n6);
p1->Insert(n7);
Monster nTemp;
p1->GetElement(6,nTemp);
printf("%d\n",nTemp);
printf("%d\n",p1->GetElementIndex(nTemp));
printf("%d\n",p1->GetSize());
p1->Traverse();
Monster nCh9(9,9,"小龙");
p1->Insert(5,nCh9);
p1->Traverse();
Monster nCh10(10,10,"大龙");
p1->Insert(nCh10);
p1->Traverse();
printf("%d\n",p1->GetSize());
p1->Delete(2);
p1->Traverse();
printf("%d\n",p1->GetSize());
getchar();
return 0;
}
通过反汇编链表中的内存分析,得到下图的链表结构:

一个问题:
如何倒序遍历链表中的结点呢?
如果你对递归的理解足够透彻,可以举一反三,把单链表当成1个二叉树,

链表就是这种特殊的二叉树,这样就可以利用二叉树的遍历方法进行递归遍历了。
然后利用二叉树的后序遍历,这就是倒序打印链表中的结点。
实现方法:
template<class T_ELE>
void LinkedList<T_ELE>::ReverTraverse(PNODE head){
if (head == NULL) {
return;
}
ReverTraverse(head->pNext);
// 后序位置
T_ELE data = head->Data;
printf("%d ",data);
}
倒序打印结果如下:


浙公网安备 33010602011771号