链式线性表

线性表的链式储存结构的实现主要有单链表,双向链表,循环链表等
,它可以根据结点需要来获取一个空间,不会造成空间浪费

1. 单链表
结点的定义

template <typename T>
struct Node 
{ 
  T data; 
  Node<T> *next;      //此处<T>也可以省略
}; 

带头结点的单链表:
头结点的数据域可以用来储存一些附加信息,指针域用来存储链表中第一个结点的地址
单链表的实现:

template <class T>
class LinkList { 
  public: 
  LinkList ( ) {first=new Node<T>; first -> next= NULL ;}//构造带头结点的空单链表
     LinkList ( T a[ ], int n ) ; 
  ~LinkList ( ) ; 
  int Length ( ) ;
  T Get ( int i ) ; 
  int Locate ( T x ) ;
  void Insert ( int i, T x ) ;
  T Delete ( int i ) ; 
  void PrintList ( ) ; 
  private: 
  	Node<T>  *first; // 单链表的头指针  , <T>可以省略
}; 

单链表的带参构造函数
头插法

template <class T>
LinkList<T>:: LinkList(T a[ ], int n) {
    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;//将s插入到头结点后面
          first->next=s;//修改头结点的指针域
	}
}

尾插法

template <class T>  
LinkList<T>:: LinkList(T a[ ], int n) {
    Node<T> *r,*s;      //s尾指针
    first=new Node<T>;   //生成头结点
	r=first;          
    for (int i=0; i<n; i++)	{ 
        s=new Node<T>; 
        s->data=a[i];  //为每个数组元素建立一个结点
        r->next=s; r=s;      //插入到终端结点之后,修改终端结点
	}
    r->next=NULL;    //单链表建立完毕,将终端结点的指针域置空
 }

尾插法并不用一直保持终端结点指针域为空,只需在链表构造完成后将它置空
单链表的遍历

template <class T>  
LinkList<T>:: PrintList()
{
    Node<T> *p;
	p=first->next;          
     while(p)
	{
		cout<<p->data;
            p=p->next;
	}
 }

补充:
不带头结点的单链表的构造
头插法:

template <class T>
LinkList<T>:: LinkList(T a[ ], int n){
    first=NULL;
    for(int i=0;i<n;i++)    { 
         s=new node<T>;
         s->data=a[i];
         s->next=first;
         first=s;   
    }
}

尾插法:

template <class T>  
LinkList<T>:: LinkList(T a[ ], int n){
node<T> *r;
    first=NULL;
    if(n<=0return;
    s=new node<T>;
    s->data=a[0];
    s->next=first;
    first=s;   
    r=first;
for(int i=1;i<n;i++)    { 
         s=new node<T>;
         s->data=a[i];
         r->next=s;
         r=s;   
    }
}

单链表中按位置查找

template <class T>
T LinkList<T>::Get(int i) {   
   Node<T> *p; int j;
   p=first->next;  j=1;  //或p=first;  j=0;
   while (p && j<i) {
      p=p->next;       //工作指针p后移
  j++;
    }
   if (!p) throw "位置";
   else return p->data;
}

单链表的插入操作(按位置进行插入)

template <class T>  
void LinkList<T>::Insert(int i, T x){  
   Node<T> *p; int j;
   p=first ; j=0;    //工作指针p初始化
   while (p && j<i-1)   {
     p=p->next;   //工作指针p后移
     j++;
   }
   if (!p) throw "位置";
    else { 
   Node<T> *s;
      s=new Node<T>; 
   s->data=x;  //向内存申请一个结点s,其数据域为x
      s->next=p->next;       //将结点s插入到结点p之后
      p->next=s; 
 }
 }

补充
不带头结点的单链表中插入结点

Insert(int i, T x){  
   Node<T> *p; int j;
   if(i<=0throw “位置非法”;
   if (i==1{ s=new Node<T>;s->next=head;head=s;return}
   p=first ; j=1;    //工作指针p初始化
   while (p && j<i-1)   {
     p=p->next;   //工作指针p后移
     j++;
   }
   if (!p) throw "位置";
    else { 
   Node<T> *s;
      s=new Node<T>; 
   s->data=x;  //向内存申请一个结点s,其数据域为x
      s->next=p->next;       //将结点s插入到结点p之后
      p->next=s; 
 }
 }

单链表中节点的删除(删除编号是i的结点)

template <class T>  
T LinkList<T>::Delete(int i){ 
  Node<T> *p; int j;
  p=first ; j=0;  //工作指针p初始化
  while (p && j<i-1) {  //查找第i-1个结点
    p=p->next; 
    j++;
  }
  if (!p || !p->next) throw "位置";  //结点p不存在或结点p的后继结点不存在
    else {
        Node<T> *q; T x;
          q=p->next; x=q->data;  //暂存被删结点
          p->next=q->next;  //摘链
          delete q; 
          return x;
 }
}

析构函数

template <class T>
LinkList<T>:: ~LinkList()
{
   Node<T> *q;
   while (first)
   {
       q=first->next;
       delete first;
       first=q;
    }
}

2.循环链表
循环链表是一种特殊的单链表
将单链表或者双链表的头尾结点链接起来,就是一个循环链表。
特点:
首尾相接的链表。
可以从任一节点出发,访问链表中的所有节点。
判断循环链表中尾结点的特点:
q->next==first
空表的构造

template <class T>
CycleLinkList<T>:: CycleLinkList( )
{
         first=new Node<T>; first->next=first;//首尾相连
}

构造非空的时候头插法就从循环链表空表开始,与单链表一模一样;尾插法就将单链表建立完毕,将终端结点的指针域置空
将非循环的单链表改造成循环的单链表

p=first;
while(p->next)
{ 
       p=p->next;  
 }
p->next=first

3.双链表
双链表的结点结构

template <class T>
struct  DNode{
 T  data;
 DNode<T> *llink;
  DNode <T>*rlink;
}; 

双向链表P之后插入结点

q->rlink=p->rlink;
P->rlink=q;
q->llink=p;
if(q->rlink)
    q->rlink->llink=q;//p存在后继结点

删除操作

p->llink->rlink=p->rlink;
 if(p->rlink)
        p->rlink->llink=p->rlink;//p存在后继结点
delete(p);

双向链表的构造-空表的构造

template <class T> 
DoubleLink <T>::DoubleLink(){
  head=new Node<T>;
  head->rlink=NULL;
  head->llink=NULL;
 }

析构函数

template <class T>
DoubleLink<T>::~DoubleLink(){
 Node<T>  *p,*q;
 p=head;
 while(p)
 {
  q=p->rlink;
  delete p;
  p=q;
  
 }
}

总结
线性表包括顺序表和链式表,各有各的优点,顺序表不需要多余的空间来表示结点之间的关系,可以任意取其中的元素;链式表插入,删除操作简单;
结论:
1.若线性表的操作主要是进行查找,很少做插入和删除时,宜采用顺序表做存储结构。
2.对于频繁进行插入和删除的线性表, 宜采用链表做存储结构。
3.当线性表的长度变化不大, 易于事先确定其大小时,为了节约存储空间,宜采用顺序表作为存储结构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值