近期学习了函数的模板以及线性表的知识。
***关于模板,模板是对参数的多态化,将数据类型进行抽象。使一段程序代码可以用于处理多种不同类型的对象,是一种参数化的多态性工具。
模板分为两类:一种是函数模板,一种是类模板。
函数模板:
template<模板形参表> (模板形参表:typename/class T)
返回值类型 函数名(参数表)
{
函数体;
}
类模板:
template<模板形参表>
Class 模板类名
{
成员声明;
}
函数模板实例化后是模板函数;类模板实例化后为模板类。
类模板中必然会出现成员函数,成员函数的在类外声明时要注意 :在声明前都要加上template<模板形参表>。每一个都要加上!!然后才是其他东西的声明
基本格式:
template<模板形参表>
返回值类型 类模板名<形参名表>::成员函数名(参数表)
{
成员函数体;
}
例外:类中的构造函数与析构函数因为没有返回值类型,所以在类外声明时不需要加上返回值类型,直接实例化即可。(实例化,记得实例化。)
***线性表的顺序存储
与数组相似,顺序存储中数据的存储位置是连续的,他是通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,支持数据的随机访问。
一个顺序表:
template <class T>
class A
{
private:
T data[100]; // 存放数据元素的数组
int length; // 线性表的长度
Private:
成员函数;
}
空表的表示方法就是存储的length=0。
***线性表的链式存储;
链式存储分为三种:单链表,双链表,循环链表。
单链表顾名思义,一个Node中存有自己的数据以及下一个的单元的存储位置。
即: template<typename T>
class Node
{
T date;
Node<T> *next;//指向下一个存储位置
}
在这里可以看出链式存储与顺序存储的一个区别就是,链式存储的存储位置是不连续的,所以链式存储不支持内存的随机访问,对于单链表只能找到first(头指针)然后挨个的往后找。
一个空的链表:另他的头指针first->next=NULL;
**构建单链表的方法:
*头插法(带头节点):
对于头插法,我们不难理解,就是将一个新的Node在头上插入一个链表中。这里就需要在插入之前先要存在这样一个链表,我们就需要创建一个空的链表,然后利用循环来不断的修改头指针first所指向的位置,以及新插入的Node所指向的位置。
代码:
{
first=new Node<T>; //生成头节点
first->next=NULL;
Node<T> *s;
for (int i=0; i<n; i++)
{
s=new Node<T>;
s->data=a[i];
s->next=first->next;
first->next=s;
}
}
(不带头节点)
{
first=NULL;//没有申请
for(int i=0;i<n;i++)
{
s=new node<T>;
s->data=a[i];
s->next=first;
first=s;
}
}
在这里,我在理解起来带头节点与不带头节点相比起来,带头的比较好理解。
*尾插法(带头节点):
尾插法相较于头插法便于理解,只需要新设一个指针不断地后移,最后将最后的指针赋空
代码:
{
first=new Node<t>;
first->next=NuLL;//这个其实没有必要,因为最后都会赋空。
Node<T>*s,*r;
for (int i=0; i<n; i++)
{
s=new Node<T>;
s->data=a[i];
r->next=s;
r=s;
}
}
通过这一个多周的学习,对于链表有了一定的认识,感觉太绕了,对于指针的指向还是拿捏不准,需要多多练习。另外在完成代码的过程中还是会出现一定的问题,有待改进。