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);
}

  

倒序打印结果如下:

 

posted @ 2023-10-16 17:35  一日学一日功  阅读(121)  评论(0)    收藏  举报