• Windows 程序设计学习记录(2)数据链表删除,增加的算法


    昨天学习了通过建立一个CSimpleList类来实现一个数据链表,通过类中的接口函数实现对数据链表中的数据的增加和删除。但是我一直没有看明白CSimpleList::AddHead(void* p)和CSimpleList::Remove(void* p)这两个实现增加和删除的接口函数:

    void CSimpleList::AddHead(void* p)
    {
        *GetNextPtr(p) = m_pHead;
        m_pHead = p;
    }
    inline void** CSimpleList::GetNextPtr(void* p) const
          { return (void**)((BYTE*)p + m_nNextOffset);}

         首先看看AddHead(void* p)这个接口函数,它的作用是把加进来的元素的地址传给m_pHead这个空指针变量,同时把原来的首元素的地址放在*GetNextPtr(p)中,这里大家应该意识到了,这个m_pHead是存放数据链表中首元素的地址的。

          这里大家又要注意一下

    void** CSimpleList::GetNextPtr(void* p) 
    这个函数的返回值是指向指针的指针类型的,
    m_nNextOffset这个是存放数据结构(就是我们的数据链表中的元素)中pNext成员的偏移量,这个是用来干什么的呢???

    我们需要知道,在数据链表中,元素中除了有自己的数据外,还包含了下一个元素的地址,这样,我们知道其中一个元素,就知道下一个元素在哪,从而整个元素(数据)表中就像有条线联系着各个元素,彼此相互联系。

    现在,关键是如何进行元素的增加和删除了:
    (1)增加元素:我们增加的这个元素会放在链表首位,同时还要给它下一个(之前的首元素)元素的地址,这样就完成了增加操作。
    (2)删除元素:删除元素有点特别,我们首先要判断这个待删除的元素是不是链表首元素,如果是首元素,则
    m_pHead = *GetNextPtr(p); //p是要删除的元素地址,这里是把首元素中记录下一元素的地址传给m_pHead,这里有点拗口啊,要细心 //理解;
    如果待删除的不是首元素,那么就要遍历整个数据链表中的元素,当我们查到某一元素的下一元素为要删除的元素时,那么就要把待删除元素中包含的下一元素地址传给当前这个元素中那个存放下一元素地址的成员;
    BOOL CSimpleList::Remove(void* p)
    {
    	if(p == NULL)    
    		return FALSE;
    
    	BOOL bResult = FALSE;     //假设移除失败
    	if(p == m_pHead)
    	{
    		//要移除头元素
    		m_pHead = *GetNextPtr(p);
    		bResult = TRUE ;
    	}
    	else
    	{
    		//试图在表中查找要移除的元素
    		void* pTest = m_pHead;
    		while(pTest != NULL && *GetNextPtr(pTest) != p)
    			pTest = *GetNextPtr(pTest);
    
    		//如果找到了,就将元素移除
    		if(pTest != NULL)
    		{
    			*GetNextPtr(pTest) = *GetNextPtr(p);
    			bResult = TRUE;
    		}
    	}
    	return bResult;
    }
    
    
    好了,现在我们知道了数据链表中增加元素和删除元素的算法了,接下来就是实践一下,这里我们在主程序中要对两个很重要的CSimpleList类中的成员变量m_nNextOffset初始化为指定的值,什么意思呢,就是要把CSimpleList类的pNext成员的偏移量传给m_nNextOffset(我们用到类中的一个内联函数Constuct(int nNextOffset)来实现这个初始化)。
    void main()
    {
    	MyThreadData* pData;
    	//CTypedSimpleList<MyThreadData*> list;
    	CSimpleList list;
    	list.Construct(offsetof(MyThreadData, pNext));   //告诉CSimpleList类pNext成员的偏移量
    
    	//向链表中添加成员
    	for( int i = 0;i<10;i++)
    	{
    		pData = new MyThreadData;
    		pData->nSomeData = i;
    		list.AddHead(pData);
    	}
    
    	//......   ........   //使用链表中的数据
    
    	//遍历整个链表,释放MyThreadData对象占用的空间
    	pData = (MyThreadData*)list.GetHead();
    	while(pData != NULL)
    	{
    		MyThreadData* pNextData = pData->pNext;
    		printf( "The value of nSomeData is: %d \n",pData->nSomeData);
    		delete pData;
    		pData = pNextData;
    	}
    }
    
    
    

      

     


  • 相关阅读:
    zabbix 监控获取源码包的地址
    为MongoDB加集群验证的关键点
    Mongodb 集群加keyFile认证
    Prometheus完整的部署方案+实战实例
    如何让你的linux的命令行变得很炫
    redis实现加锁的几种方法示例详解
    phpquerylist 抓取数据详解
    mysql 主从配置,主-》windows,从-》centos6.5
    VMware 虚拟机centos下链接网络配置
    【Mysql】表链接
  • 原文地址:https://www.cnblogs.com/YungMing/p/2500710.html
Copyright © 2020-2023  润新知