线性表——链表

一、指针变量

变量的三要素
名字,内存地址,值
变量的左值,右值
左值指变量的内存地址
右值:值
在赋值表达式中,赋值号左边需要左值,右边需要右值;如a=a+100
指针变量
指针变量的右值本身又是一个左值

二、单链表结点

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>可以省略
}; 

四、单链表构造

1.头插法(带头节点)
建立在这里插入图片描述

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;
          first->next=s;
	}
}

头插法(不带头节点

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

2.尾插法(带节点)

在这里插入图片描述

template <class T>  
LinkList<T>:: LinkList(T a[ ], int n) {
    Node<T> *r,*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;    //单链表建立完毕,将终端结点的指针域置空
 }

尾插法(不带头节点)

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

五、单链表遍历

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

六·、按位查找

1 工作指针P初始化,计数器初始化
2 执行下列操作,直到p为空或指向第i个节点
2.1 工作指针后移
2.2 计数器增1
3 若p为空,则第i个元素不存在,抛出位置异常;否则查找成功,返回节点p的数据元素

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;
}

七、插入

1 工作指针p初始化,计数器初始化
2 查找第i-1个节点,并使工作指针p指向该节点
3 若查找不成功(P==NULL),说明位置错误,抛出位置异常,否则
3.1 生成一个元素值为x的新节点s
3.2 将s插入到p之后

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;	
	}
 }

八、删除

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;
    }
}

十、单链表和顺序表对比

若线性表的操作主要是进行查找,很少做插入和删除时,宜采用顺序表做存储结构
因此,对于频繁进行插入和删除的线性表, 宜采用链表做存储结构

十一、循环链表

将单链表或者双链表的头尾结点链接起来,就是一个循环链表。
不增加额外存储花销,却给不少操作带来了方便
从循环表中任一结点出发,都能访问到表中其他结点。

创建结点

template <class T>
struct Node
{
   T data;
   Node<T> *next;
};

链表的实现

template <class T>
class CycleLinkList{
  public:
    CycleLinkList( ); 
    CycleLinkList(T a[ ], int n);  
    CycleLinkList(T a[ ], int n,int i);
    ~CycleLinkList();           
    int Length();        
    T Get(int i);          
     void Insert(int i, T x);
    T Delete(int i);        
    void PrintList( );    
 private:
   Node<T> *first;  
};

构建空表

template <class T>
CycleLinkList<T>:: CycleLinkList( )
{
         first=new Node<T>; first->next=first;
}

尾插表构建循环链表

template <class T>  
CycleLinkList<T>:: CycleLinkList(T a[ ], int n) {
    first=new Node<T>;   //生成头结点
	Node<T> *r,*s;
     r=first;          //尾指针初始化
    for (int i=0; i<n; i++)	{ 
        s=new Node<T>; 
        s->data=a[i];  
        r->next=s; 
         r=s;     
	}
    r->next=first;    //单链表建立完毕,将终端结点的指针域指向头结点
 }

头插法构建循环链表

template <class T>  
CycleLinkList<T>:: CycleLinkList(T a[ ], int n,int k)
 {
    first=new Node<T>;   //生成头结点
	first->next=first;
	Node<T> *s;
	for (int i=1; i<n; i++)
	{ 
      s=new Node<T>; 
	  s->data=a[i];  //为每个数组元素建立一个结点
      s->next=first->next;
	  first->next=s;
	}
}

十二、双链表

结点

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

结构特点:

由于在双向链表中既有前向链又有后向链,寻找任一个结点的直接前驱结点与直接后继结点变得非常方便。设指针p指向双链表中某一结点,则有下式成立:

p->llink->rlink = p = p->rlink->llink

双向链表实现

template <class T>
class DoubleLink {
private:
	Node<T> *head;
public:
	DoubleLink()~DoubleLink();
	void Append(T data);
	void Display();
	void Insert(int locate , T data);
	T    Get(int locate);
	T	 Delete(int locate);
};

双向链表构建

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

头插

template <class T>
void DoubleLink<T>::Append(T data){
	      Node<T> *s;
     	s=new Node<T>;
	       s->data=data;
		s->rlink=head->rlink;
		head->rlink=s;
		s->llink=head;
		if (s->rlink)
			s->rlink->llink=s;
		return;
}

遍历

template <class T>
void DoubleLink<T>::Display(){
	Node <T> *p;
	p=head->rlink;
	while(p)	{
		cout<<p->data<<"   ";
		p=p->rlink;
	}
	cout<<endl;
	return;
}

十三、静态链表

静态链表的必要性:某些程序设计语言不支持指针类型
特点:用顺序存储结构(数组)模拟实现链表
在这里插入图片描述
优点:
插入和删除时不需要移动元素,直接修改指针即可,因此效率较高
缺点:
静态链表是借助于数组实现的,因此,不能动态的修改数组的大小,存在着跟静态数组一样不能按需进行存储空间的分配

十四、间接寻址(指针数组)

线性表的顺序存储的优点:支持随机访问
线性表的链式存储的优点:插入和删除数据时不需要移动数据
间接寻址:将指针和数组结合起来的一种方法
它将数组中的存储数据元素的单元改为存储指向该元素的指针

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值