#pragma once
/**
*原理很简单,将数组的元素看成是链表,或者说是数组空间起到了内存池的作用。然后用两个结点表示
*当前使用/空闲的链表
*
*对效率问题上的一些说明
*增:这个无需说,链表直接秒杀。
*删:类里提供的是一个ELEMENT结构,里面包含了用户的数据。如果你想保持常量的效率
*在一些数据接口提供是,也必须用ELEMENT,这样才能记住结点信息。否则你可以单开个你自己数据类型的接口
*但是在删除时,就必须遍历(删除方法见提供的实例)
*ELEMENT类型的快速使用:typedef CListWithArray<int,1000>::ELEMENT CListWithArray_t;
*你维护好CListWithArray_t就行
*提供以下接口
* bool Add(llist_t* e); //返回一个表示是否插入成功的标志。
* llist_t* Erase(); //取的结点的下一个元素,并且原链表中删除
* 将next提供给使用者,无需太多的其他接口,可以满足大部分要求
**/
namespace list_with_array
{
template<typename llist_t, int llist_size=100>
class CListWithArray
{
//variable
public:
struct ELEMENT
{
llist_t element;
ELEMENT* pPre;
ELEMENT* pNext;
};
private:
ELEMENT elementData[llist_size];//数组空间
ELEMENT freeElement; //空余的指针链头
ELEMENT useElement; //当前使用的指针链头
//function
public:
CListWithArray();
bool Add(const llist_t e);
ELEMENT* Erase(ELEMENT *p)
{
return ReleaseElement(p);
}
ELEMENT* GetListHead()
{
return useElement.pNext;
}
/**
*信息的一些监控
**/
int GetSumUseElement()
{
int sum=0;
ELEMENT* p;
for(p=useElement.pNext; p!=NULL; p=p->pNext)
{
++sum;
}
return sum;
}
int GetSumFreeElement()
{
int sum=0;
ELEMENT* p;
for(p=freeElement.pNext; p!=NULL; p=p->pNext)
{
++sum;
}
return sum;
}
private:
/**
*初始链表串,双指针链表
**/
void InitList();
ELEMENT* MallocElement();
ELEMENT* ReleaseElement(ELEMENT *p);
/**
*将一个结点加入到目的链表
**/
void AddNodeToList(ELEMENT* const pNode, ELEMENT* const pDesList)
{
//处理好结点头尾
pNode->pNext = pDesList->pNext;
pNode->pPre = pDesList;
//判断是否已经有元素,以便前置变量的赋值
if( NULL!=pDesList->pNext )
{
pDesList->pNext->pPre = pNode;
}
pDesList->pNext = pNode;
}
};
/**
*这里是大函数体定义
**/
template <typename llist_t, int llist_size>
CListWithArray<llist_t, llist_size>::CListWithArray()
{
InitList();
}
template <typename llist_t, int llist_size>
void CListWithArray<llist_t, llist_size>::InitList()
{
//开始串指针
for(int i=0; i<llist_size-1; ++i)
{
elementData[i].pNext = &elementData[i+1];
}
elementData[llist_size-1].pNext = NULL;
useElement.pNext = NULL;
freeElement.pNext = &elementData[0];
}
template <typename llist_t, int llist_size>
typename CListWithArray<llist_t, llist_size>::ELEMENT* CListWithArray<llist_t, llist_size>::MallocElement()
{
//判断是否有空余元素
if( NULL==freeElement.pNext )
{
return NULL;
}
//从Free链中脱出,头部
ELEMENT* p = freeElement.pNext;
freeElement.pNext = freeElement.pNext->pNext;
//空运的状态
p->pPre = NULL;
p->pNext = NULL;
AddNodeToList(p, &useElement);
return p;
}
template <typename llist_t, int llist_size>
typename CListWithArray<llist_t, llist_size>::ELEMENT* CListWithArray<llist_t, llist_size>::ReleaseElement( ELEMENT *p)
{
ELEMENT *pResult = p->pNext;
//从Use链中脱离
p->pPre->pNext = p->pNext;
//判断是否是尾元素
if( NULL!=p->pNext )
{
p->pNext->pPre = p->pPre;
}
//空运状态
p->pPre = NULL;
p->pNext = NULL;
AddNodeToList(p, &freeElement);
return pResult;
}
template <typename llist_t, int llist_size>
bool CListWithArray<llist_t, llist_size>::Add(const llist_t e)
{
//先从Free指针里取得一个空节点
ELEMENT *p = MallocElement();
if( NULL==p )
{
return false;
}
else
{
p->element = e;
return true;
}
}
};
/*
使用方法
#include "CListWithArray.h"
using namespace std;
using namespace list_with_array;
CListWithArray<int,1000> listTest;
typedef CListWithArray<int,1000>::ELEMENT CListWithArray_t;
void cout_listinfo()
{
cout<<"sum use:"<<listTest.GetSumUseElement()<<endl;
cout<<"sum free:"<<listTest.GetSumFreeElement()<<endl;
cout<<"-------------------"<<endl;
}
void test_del_1()
{
CListWithArray_t *p=listTest.GetListHead();
while( NULL!=p )
{
if( ((p->element)&0x1) == 0 ) //删掉奇数
{
p = listTest.Erase(p); //注意,这里p的信息已经被修改,无需再p->pNext;
continue;
}
p=p->pNext;
}
}
void test_del_2()
{
CListWithArray_t *p=listTest.GetListHead();
while( NULL!=p )
{
if( 1000==p->element || 2000==p->element )
{
p = listTest.Erase(p);
continue;
}
p=p->pNext;
}
}
void test_add_1()
{
for(int i=0; i<1100; ++i)
{
listTest.Add(i);
}
}
void test_add_2()
{
for(int i=0; i<3; ++i)
{
listTest.Add(i*1000);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
cout_listinfo(); //链表最早状态
test_add_1(); //加满链表
cout_listinfo();
test_del_1(); //删除奇数
cout_listinfo();
test_add_2(); //压入个特殊数,0,1000,2000
cout_listinfo();
test_del_2(); //删除1000,2000
cout_listinfo();
return 0;
}
*/
分享到:
相关推荐
"C++数组模拟链表" C++中的链表是数据结构中非常重要的一...数组模拟链表是一种非常有用的技术,可以用于实现链表的插入和遍历操作。通过使用数组模拟链表,我们可以避免使用指针,减少代码的复杂度和出错的可能性。
纯手写 java 数组模拟链表约瑟夫环问题 有很大更改空间 仅供参考
在本文中,我们将详细介绍如何模拟Java的HashMap集合,使用数组和链表来实现Hash表的存储。我们将从基本概念开始,逐步深入到HashMap的实现细节中。 什么是HashMap? HashMap是一种基于散列表的数据结构,用于存储...
然而,使用数组来模拟链表可能在某些情况下具有一定的优势,例如在特定场景下可以利用数组的索引访问特性。 首先,我们需要定义一个节点类,它包含两个属性:数据和指向下一个节点的引用。在Java中,这可以通过创建...
在PHP中,虽然没有内置的链表类型,但可以通过对象和引用模拟链表。链表的优点在于插入和删除操作高效,只需改变相邻节点的指针即可,但访问速度相对较慢,因为需要遍历指针链。 2. **内存分配** - **数组**:数组...
在这个错误版本的实现中,开发者可能尝试通过数组来模拟链表的一些特性,如动态增长、插入和删除操作。然而,由于数组和链表的本质区别,这种实现可能会遇到一些挑战。 首先,链表的主要优势之一是动态扩展性。链表...
动态数组实现链表的核心思想是利用动态数组的特性来模拟链表的行为。下面我们将详细讨论这个实现过程: 1. **节点表示**:首先,我们需要定义链表节点的结构。在动态数组中,我们可以创建一个结构体或类,包含数据...
约瑟夫环问题,也被称为...无论是数组还是链表实现,都需要对数据结构有深入的理解,并能够根据问题特点灵活选择合适的方法。在实际应用中,我们可以根据问题规模、内存限制以及计算性能要求,来决定采用哪种实现方式。
有些语言不提供指针与对象数据类型,以下代码通过多重数组实现链表结构及其基本操作。 用一个数组空间模拟分配堆。用一个头指针为free的链表来管理自由空间。用栈得push和pop操作来实现释放和分配空间。 三个数组...
### 练习题-数组双向链表 #### 概述 本练习题旨在帮助初学者理解如何使用数组来实现双向链表的基本...通过以上练习题的实现,学习者不仅可以掌握数组实现双向链表的方法,还能深入了解链表操作背后的原理和技术要点。
4. **其他数据结构和算法**:"杨辉三角"和"金字塔杨辉三角"是典型的递归问题,可以用数组或链表实现,涉及到组合数学和二项式系数。"螺旋数组"是数组的一种特殊排列,可以通过多维数组和循环实现。"魔方数组"可能是...
在本题目中,我们面临的是一个数据结构相关的编程挑战,具体来说是关于数组和链表的应用。题目名为"圆桌问题",这是一个经典的问题,旨在测试程序员对数据结构的理解以及解决问题的能力。在这个问题中,我们需要处理...
本主题探讨了多种方法来实现这一目标,包括使用数组、链表、数据库和堆栈等数据结构。这些不同的方法展示了如何利用各种编程技巧来解决同一个问题。 首先,数组是最基础的数据结构之一,它在内存中连续存储元素。在...
在本报告中,我们将探讨操作系统(如Windows或Unix)的自举过程,以及如何使用数组模拟内存来实现内存管理。自举是操作系统启动的关键阶段,而数组模拟内存则是理解内存管理概念的有效手段。 一、操作系统自举的...
由于链表的节点不是连续存储的,因此不适合使用普通数组,而应使用动态数组来模拟链表的行为。 在“C语言数组_C语言实现使用动态数组来构建循环链表”这个主题中,我们将探讨如何使用动态数组来实现循环链表的主要...
Java中有ArrayList和LinkedList两种链表实现,前者基于数组,后者基于链式节点。项目可能模拟了这些链表的操作,如添加、删除、查找和遍历。 树是一种非线性数据结构,每个节点可以有零个或多个子节点。常见的树...
总结起来,这个压缩包文件提供了关于链表和数组栈的知识点,包括链表的基本概念、Python中如何模拟链表、数组栈的LIFO原理以及如何用链表实现数组栈以提高性能。通过学习这些内容,你可以深化对数据结构的理解,提升...
这个实验报告展示了如何用数组模拟循环链表解决约瑟夫环问题,同时也体现了问题求解的算法设计和实现能力。通过此实验,可以学习到数组操作、循环控制以及动态更新数据结构的方法。在实际编程中,类似的思路可以应用...
这个名为"go的基础数据结构的实现,包括动态数组、链表、堆、栈、集合、索引、二分搜索树、avl树、红黑树等.zip"的压缩包提供了一系列用Go实现的数据结构的源代码。下面将详细探讨这些数据结构的原理及其在Go中的...