由结点集N以及定义在结点集N上的线性关系R
(1)有一个唯一的开始节点,无前驱,有唯一后继
(2)对于有限集N 存在一个唯一的终止结点,无后继,有唯一前驱
(3)其他为内部结点,有唯一前驱和唯一后继
(4)线性表的节点个数称为长度,长度为0线性表称为空表
(5) 线性关系R简称前驱关系,应具有反对称和传递性
取值空间+运算集
template <class ELEM>
class list
{
list()=default;
~list();
void clear();
void append(ELEM value);//尾部增加新元素
int length;
void insert(int i,ELEM value);
void remove(int i);
ELEM fetch(int i);//返回值
}
(1) 创建实例
(2) 消除实例并释放空间
(3) 获取信息比如读取元素内容,由内容寻找位置
(4)访问线性表并改变内容或者结构
(5) 辅助操作 比如统计长度
元素类型相同;元素顺序存储
每个元素占用L个存储单元,顺序表开始结点 k 0 k_0 k0的存储位置记为 b = l o c ( k 0 ) b=loc(k_0) b=loc(k0) 称为顺序表的首地址或者基地址,故下标为i的元素地址为 l o c ( k i ) = b + i × L loc(k_i)=b+i\times L loc(ki)=b+i×L
顺序表是一种随机存取的结构,两个物理位置相邻的元素互为前驱和后继,故物理相邻反映了逻辑相邻
用一组任意的存储单元存储线性表的数据元素,其中存储数据元素的域称为数据域,存储直接后继位置的域称为指针域。n个这样的结点连接成一个链表。
template <class ELEM>
class ListNode
{
ELEM val;
ListNode<ELEM> *next;
ListNode(ELEM _val, const LinkNode<ELEM>* nextptr=nullptr):val(_val),next(nextptr){}
ListNode(const LinkNode<ELEM>* nextptr):next(nextptr){}
}
void Insert(LinkedList &L, int i, int e)
{
ListNode* p = FindIndex(L,i);
auto ptr = new ListNode(L,e);
ptr->next=p->next;
p->next=ptr;
return;
}
void Delete(LinkedList &L, int i)
{
ListNode* p = FindIndex(L,i);
ListNode* p_prev = FindIndex(L,i-1);
p_prev->next=p->next;
if(p!=nullptr)
delete p;
return;
}
O(n)
因为在第n个结点前插入或者删除结点,必须首先寻找到该结点的前驱单向链表想找某结点的前驱需要从头结点开始遍历链表,故采用双向链表简化操作。双向链表中有两个指针域,一个指示直接前驱,一个指示直接后继
插入
void ListInsert(DualLink &d,int i, int val)
{
auto p =FindIndex(d,i-1);
if(!p)
reurn;
auto q = new ListNode(val);
q->next=p->next;
q->prev=p;
p->next->prev=q;
p->next=q;
return;
}
void ListDelete(DualLink &d,int i)
{
auto p =FindIndex(d,i);
if(!p)
return;
p->next->prev=p->prev;
p->prev->next=p->next;
p->next=nullptr;
p->next=nullptr;
delete p;
return;
}
循环链表的最后一个结点的指针域指向头结点,操作与线性链表基本一致,但是判断是否尾结点的条件为tail->next==head
而非tail->next==nullptr;
限制访问的线性表,LIFO,有插入和弹出操作,表首被称为栈顶,栈的另一端为栈底,
分为顺序栈和链式栈(指针方向从栈顶向下链接)
void Stack::Push(float item)
{
assert(!IsFull());//判断栈满
top++;
ElmList[top]=item;
}
float Stak::Pop()
{
assert(!IsEmpty());
return ElmList[top--];
}
void hanoi(int n,char X,char Y,char Z)
{
if(n<=1)
move(X,Z);
else
{
hanoi(n-1,X,Z,Y);//X移动到Y 以Z为中转
move(X,Z);
hanoi(n-1,Y,X,Z)//Y移动到Z 以X中转
}
}
先进先出表,
template <class T>
class Queue
{
public:
void clear();
bool enQueue(const T item);
bool deQueue(T& item);
bool geFront(T& item);
bool isEmpty();
bool isFull();
}
链式队列不需要判断队列是否满,常用的存储结构有顺序队列和链式队列