数据结构(二):线性表的使用原则以及链表的应用-稀疏矩阵的三元组表示

上一篇博文中主要总结线性表中的链式存储结构实现,比方单向链表、循环链表。还通过对照链表和顺序表的多项式的存储表示。说明链表的长处。能够參看上篇博文http://blog.csdn.net/lg1259156776/article/details/47018813

以下先对没有介绍的链表中的双链表进行介绍。并通过稀疏矩阵的三元组的链式结构来深入理解较为复杂的链表存储结构。

最后对三次博文所讲述的内容进行梳理。以帮助在实际应用中选择最合适的存储结构:顺序表和链表。来组织实现自己的算法和功能。

双向链表

以下用示意图对照一下几种链表的表示:

单向链表表头

单向链表的结构例如以下:

循环链表的结构例如以下:


在循环单链表中,从随意一个结点出发,沿着向后链可以訪问到表中的全部元素;
对循环链表的操作与普通单链表基本同样,仅仅是判表空和推断表尾元素的条件有所不同

推断表尾:p->next == head
推断表空:head->next == head

双向链表

指在前驱和后继方向都能遍历的线性链表,每一个结点结构例如以下图所看到的:

双向链表结构例如以下:


双向链表的长处是:实现双向查找(单链表不easy做到),缺点是:空间开销大。

双向链表通常採用带表头结点的循环链表形式。结构例如以下:


双向链表结点CDNode的抽象数据类型:

typedef struct CDNode
{
DataType m_dData;
CDNode *m_pNext, *m_pPrev;
}

CDNode的基本操作例如以下:

void SetDNode(DNode *front);
DNode *GetPrev(DNode *ptr);
 DNode *GetNext(DNode *ptr);
void InsertPrev(DNode *pNode);
void InsertNext(DNode *pNode);
Void DeleteDNode(DNode *ptr);

双向链表CDList的实现:

typedef CDList
{
CDNode *m_pHead;
int Size;
}

CDList的基本操作:

Void SetDLList();//构造 
Void FreeDLList();//析构
int DLListSize (); 
int DLListIsEmpty();//
int DLListLocate();
 DataType DLListGetData();
 void DLListInsert();
 void DLListDelete();

针对几个比較抽象的操作进行图例说明:




********************************************************************************************

注:在链表的操作中要注意改动指针的顺序

********************************************************************************************

有序表

有序表的插入

在有顺序表L中插入新的结点,使得L仍然有序

void  OrderInsert( SqList  L, ElemType x )   {  
 //L非递减有序的顺序表。插入新元素x,使L仍然有序
   i=L.length-1; //i指向表尾元素
   while(i>=0 && x<L.elem[i]) {  
    L.elem[i+1]=L.elem[i]; //大于x的元素右移
i--;
   } //while
   L.elem[i+1]=x; L.length++;
} //OrderInser


void  OrderInsert( LinkList *L, ElemType e )   { 

 //L是带头结点且非递减有序的单链表,插入新元素e,使L仍然有序

   p=L;

   while(p->next!=NULL &&p->next->data<e)  

       p=p->next;      //找插入位置

   s=(LNode*)malloc(sizeof(LNode));

   s->next=p->next; s->data=e;

   p->next=s;

//OrderInsert  O(n)


有序表的合并

使得合并后的表仍然有序:

void  MergeList( LinkList *La,  LinkList *Lb )   { 

 //LaLb是带头结点且非递减有序的单链表。将他们归并成Lc

   pa=La->next;  pb=Lb->next;

   Lc=pc=La;  //La的头结点作为Lc的头结点

   while(pa&& pb)

   if(pa->data<=pb>data)

                   {

            pc->next=pa; pc=pa; pa=pa->next;

                   }

           else {

  pc->next=pb; pc=pb; pb=pb->next;

                    }

   pc->next = pa? pa : pb;

   delete Lb;

}   

链表应用:稀疏矩阵

稀疏矩阵:仅仅有少数非 0 矩阵元素
顺序结构:

三元组顺序表: (i,j,data)
Typedef struct{
Int I,j;
DataType item;
}Triple;


Typedef struct{
Triple  data[MaxSize+1];
Int mu,nu,tu;
}TSMatrix;

在矩阵操作时矩阵非零元素会发生动态变化,用稀疏矩阵的链接表示可适应这样的情况
稀疏矩阵的链接表示採用正交链表:行链表列链表十字交叉
行链表与列链表都是带表头结点的循环链表用表头结点表征是第几行,第几列。


稀疏矩阵的行列表头结点结构:0行0列表头结点共用一个表头结点。

列表头:next: 给出下一个列表头结点地址;down:给出本列中第一个非0矩阵元素结点地址

行表头:right:给出本行中第一个非0矩阵元素结点地址


给出稀疏矩阵的正交链表表示的图示:


数据结构的实现:

type struct OLNode
{
          int i,j;//row,col
          DataType e;
          struct OLNode *rnext,*cnext;
}OLNode,OLink


typedef struct{
OLink *rhead,*chead;
int m,n,t;
}

线性表总结

下面几个纲要是线性表的最基本的内容:

<1>  线性表的逻辑结构和各种存储表示方法

<2>  定义在逻辑结构上的各种基本运算(操作)

<3>  在各种存储结构上怎样实现这些基本运算

<4>  各种基本运算的时间复杂性

<5>  线性表的长度是否能预先确定?处理过程中变化范围怎样? 

长度确定、变化小时用顺序表
长度变化大、难以预计最大长度时宜採用链表

<6>  对线性表的操作形式怎样? 

查询操作多、删除和插入操作少时使用顺序表
频繁插入和删除操作宜採用链表 

*************************************************************************************************************************************


原文地址:https://www.cnblogs.com/gavanwanggw/p/6817118.html