线性表的定义
线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列。
名词:表长n,表头/表尾元素,空表
特点:元素有限,唯一前驱后继,有序,每个元素数据类型相同
线性表的顺序表示(数组描述)
c语言
静态分配类定义
#define MaxSize 50
typedef struct {
ElemType data [MaxSize];
int length;
}SqList;
动态分配(不是链式存储,是随机存取的顺序存储)
#define InitSize 100
typedef struct {
ElemType *data;
int MaxSize, length;
} SeqList;
//初始分配语句 c语言
L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);
//c++
L.data=new ElemType[InitSize];
c++类声明(动态分配)
class与struct:c++保留了struct向下兼容。可直接访问struct成员变量,而class的成员变量默认私有,不能直接访问要通过public中的成员函数访问。
#include <iostream.h>
#include <stdlib.h>
const int defaultSize = 100;
template <class T>
class SeqList {
protected:
T *data;
int maxSize,length;
void reSize(int newSize);//改变数组空间大小
public:
SeqList(int sz = defaultSize);
SeqList(SeqList<T>& L);
~SeqList(){delete[] data;}
//const让这个函数不能改变数据成员的值同时这个函数也不能调用非const函数
int Size()const{return maxSize;}
int Length()const{return length;}
int Search(T& x)const;//搜索x在表中位置返回序号
bool getData(int i, T& x)const
{if(i>0&&i<=length){x=data[i-1];return true;}else return false;}//取第i个值
void setData(int i, T& x)
{if(i>0&&i<=length)data[i-1]=x;}//修改第i个值
bool Insert(int i, T& x);//在第i个后插入x
bool Remove(int i, T& x);
bool isEmpty(){return(length==0) ? true : false;}
bool isFull(){return(length==maxSize) ? true :false;}
void input();
void output();
SeqList<T> operator=(SeqList<T>& T);//重载=操作符
};
注:动态分配虽然可以扩充空间,但需要移动大量元素,操作效率低。
顺序表的特点
- 各个表项逻辑顺序和物理顺序一致——插入和删除需要移动大量元素
- 可以顺序访问、随机访问,访问每个元素的时间相同
- 存储密度高(每个结点只存数据元素)
- 静态分配浪费空间
线性表的链式表示(单链表且动态分配)
c语言
结点
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
c++
结点
template<class T>
struct LNode{
T data;
LNode<T> *next;
LNode(LNode<T> * ptr = NULL){next=ptr;}//仅初始化指针next的构造函数
LNode(const T& item,LNode<T> *ptr=NULL){data=item;next=ptr;}//初始化数据和指针的构造函数
};
链表
template<class T>
class List{
public:
List(){first = new LNode<T>;}
List(const T& x){first = new LNode(x);}
List(List<T>& L);
~List(){makeEmpty();}
void makeEmpty();
int Length();
LNode<T> *getHead(){return first;}
LNode<T> *search(T x);
LNode<T> *Locate(int i);
bool getData(int i,T& x);
bool setData(int i,T& x);
bool Insert(int i,T& x);
bool Remove(int i,T& x);
bool IsEmpty(){return first ->next == NULL ? true : false;}
void Sort();
void inputFront(T endTag);//前插法建立链表
void inputRear(T endTag);//尾插法建立链表
void output();
List<T>& opreator=(List<T>& T);
protected:
LNode<T> *first;//头结点
};
初始化实现
template<class T>
void List<T>:: inputFront(T endTag){//头插法
LNode<T> *newNode; T val;
makeEmpty();
cin>>val;
while(val!=endTag){
newNode =new LNode<T>(val);
if(newNode==NULL){cerr<<"存储分配错误"<<end1;exit(1);}
newNode->next=first->next;//插入头结点后
first->next=newNode;//新结点成为头结点后一个
cin>>val;
}
};
template<class T>
void List<T>:: inputRear(T endTag){//尾插法
LNode<T> *newNode,*last; T val;
makeEmpty();
cin>>val;last=first;
while(val!=endTag){
newNode =new LNode<T>(val);//按照定义的构造方法,newNode->next==NULL
if(newNode==NULL){cerr<<"存储分配错误"<<end1;exit(1);}
last->next=newNode;//插入末尾
last=newNode;//新结点成为新尾
cin>>val;
}
};
双链表、循环链表、静态链表
双链表 c语言
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode, *DLinkList;
仅比单链表增加一个前驱指针*prior
双链表 c++
template<class T>
struct DNode{
T data;
DNode<T> *prior,*next;
//仅初始化指针的构造函数
DNode(DNode<T> * left = NULL,DNode<T> * right = NULL){prior=left;next=right;}
//初始化数据和指针的构造函数
DNode(const T& item,DNode<T> *left=NULL,DNode<T> * right = NULL)
{data=item;prior=left;next=right;}
};
循环链表-循环单链表
注:最后一个结点指向头,注意判空条件不是头结点指空,而是头指针指向头结点
bool IsEmpty(){return first->next == first;}
类定义与普通单链表相同。
特点:只要知道表中任意结点指针就能遍历表中其他任何结点;可以通过设置尾指针简化插入删除运算实现。
循环链表-循环双链表
判空不同。
bool IsEmpty(){return first->next == first;}
类定义与普通双链表相同。
静态链表
c语言
#define MaxSize50
typedef struct{
ElemType data;
int next;
}SLinkList[MaxSize];
注:结束标志为next==-1;插入删除只修改指针不移动元素 ;适合应用在不支持指针的高级语言中(如Basic)