线性表

一世执手 提交于 2019-12-06 11:40:32

一、基本概念

  • 线性表:由n(n>=0)个数据特性相同的元素构成的有限序列称为线性表。线性表中元素的个数n定义为线性表的长度,n=0时称为空表。
  1. 顺序表:是线性表的顺序存储结构的一种别称。
  • 特点:是以“存储位置相邻”表示两个元素之间的前驱、后继关系。
  • 优点:是可以随机存取表中任意一个元素。
  • 缺点:是每作一次插入或删除操作时,平均来说必须移动表中一半元素。 常应用于主要是为查询而很少作插入和删除操作,表长变化不大的线性表。
  1. 链表:是线性表的链式存储结构的别称。
  • 特点:是以“指针”指示后继元素,因此线性表的元素可以存储在存储器中任意一组存储单元中。
  • 优点:是便于进行插入和删除操作。
  • 缺点:是不能进行随机存取,每个元素的存储位置都存放在其前驱元素的指针域中,为取得表中任意一个数据元素都必须从第一个数据元素起查询。

二、线性表的表示与实现

1、顺序表示和实现

#include <iostream>
using  namespace std;

//顺序表的存储结构,ElemType假设为int
#define  MAXSIZE  100
typedef struct{
 int *elem;
 int length;
}SqList;

//顺序表的初始化
bool InitList(SqList &amp;list){
    list.elem =new int[MAXSIZE];
    list.length=0;
    return true;
};

//顺序表的取值
bool GetElem(SqList list,int i,int &amp;e){
    if(i&lt;1||i&gt;list.length){
        return false;
    } else{
        e=list.elem[i-1];
        return true;
    }
}

//顺序表的插入,将e插入位置i
bool ListInsert(SqList &amp;list,int i,int e){
    if(i&lt;1||(i&gt;list.length+1)){
        return false;
    } else if(list.length==MAXSIZE){
        return false;
    } else{
        int len = list.length;
        for (int j = (len-1); j &gt;=(i-1); j--) {
            list.elem[j+1]=list.elem[j];
        }
        list.elem[i-1]=e;
        list.length++;
        return true;
    }
}

//顺序表的删除
bool ListDelete(SqList &amp;list,int i){
    if (i&lt;1||i&gt;(list.length+1)){
        return false;
    }else{
        int len = list.length;
        for (int j = i-1; j &lt;=len-1 ; j++) {
            list.elem[j]=list.elem[j+1];
        }
        list.length--;
        return true;
    }
}

//顺序表的输出
void ListDisplay(SqList sqList){
    for (int i = 0; i &lt; sqList.length; ++i) {
        cout&lt;&lt; sqList.elem[i];
    }
    cout&lt;<endl; } ``` ## 2、链式表示和实现 ```cpp #include <iostream>
#define ElemType int 
#define OK true
#define ERROR false
#define Status bool

typedef struct LNode
{
    ElemType data;
    struct LNode* next;
}LNode, * LinkList;

//单链表的初始化,构造一个空的单链表
Status InitList(LinkList&amp; L) {
    L = (LinkList)malloc(sizeof(LinkList));
    L-&gt;next = NULL;
    return OK;
}

//在带头结点的单链表L中第i个位置之前插入元素e
Status ListInsert(LinkList&amp; L, int i, int e) {
    LinkList p = L;
    int j = 0;

    while (p &amp;&amp; j &lt; (i - 1)) { p = p-&gt;next; j++; }
    if (!p||j&gt;i-1){ return ERROR; }
    
    LinkList  s = (LinkList)malloc(sizeof(LinkList));
    s-&gt;data = e; s-&gt;next = p-&gt;next; p-&gt;next = s;
    return OK;
}
//单链表的删除,在带头结点的单链表L中,删除第i个元素
Status ListDelete(LinkList&amp; L, int i) {
    LinkList p = L; LinkList q;
    int j = 0;

    while (p &amp;&amp; j &lt; i - 1) { p = p-&gt;next; j++; }
    if (!p || j &gt; i - 1) { return ERROR; }

    q = p-&gt;next; p-&gt;next = q-&gt;next; free(q);
    return OK;
}

//在带头结点的单链表L中根据序号i获取元素的值,用e返回
void GetElem(LinkList&amp; L, int i, int&amp; e) {
    LinkList  p = L-&gt;next;
    int j = 1;
    while (j &lt; i &amp;&amp; p) {
        p = p-&gt;next;
        j++;
    }
    e = p-&gt;data;
}
//头插法创建带头结点的单链表
void createList_H(LinkList&amp; L, int n) {
    L = (LinkList)malloc(sizeof(LinkList));
    L-&gt;next = NULL;
    LinkList p;
    for (int i = 0; i &lt; n; ++i) {
        p = (LinkList)malloc(sizeof(LinkList));
        scanf_s("%d",&amp;p-&gt;data);
        p-&gt;next = L-&gt;next;
        L-&gt;next = p;
    }
}
//尾插法创建带头结点的单链表
void createList_R(LinkList&amp; L, int n) {
    L = new LNode;
    L-&gt;next = NULL;
    LinkList p, rear=L;
    for (int i = 0; i &lt; n; ++i) {
        p = (LinkList)malloc(sizeof(LinkList));
        scanf_s("%d", &amp;p-&gt;data);
        p-&gt;next = NULL; rear-&gt;next = p; rear = p;
    }
}
//在带头结点的单链表中查找值为e的元素
LinkList LocateElem(LinkList L, int e) {
    LinkList  p = L-&gt;next;
    while (p-&gt;data != e) {
        p = p-&gt;next;
    }
    return  p;
}
//单链表的遍历
void displayList(LinkList L) {
    while (L != NULL) {
        L = L-&gt;next;
        printf("%d ",L-&gt;data);
    }
}

//已知单链表La和Lb的元素按值非递减排列
//归并La和Lb得到新的单链表Lc,元素也按值非递减排列
void MergeList_L(LinkList&amp; La, LinkList&amp; Lb,LinkList&amp; Lc) {
    LinkList pa, pb,pc;
    pa = La-&gt;next; pb = pb-&gt;next; 
    Lc = pc = La;  //用La的头结点作为Lc的头结点
    while (pa&amp;&amp;pb){
        if (pa-&gt;data&lt;=pb-&gt;data){
            pc-&gt;next = pa; pc = pa; pa = pa-&gt;next;
        }
        else{
            pc-&gt;next = pb; pc = pb; pb = pb-&gt;next;
        }
    }
    pc-&gt;next = pa ? pa : pb;
    free(Lb); //释放Lb的头结点

}
int main()
{
    std::cout &lt;&lt; "Hello World!\n";
}

顺序表和链表的比较

三、循环链表、双向链表

1、循环链表

>循环链表是另一种形式的链式存储结构。其特点是表中的最后一个结点的指针指向头结点。整个链表形成一个环。由此,从表中的任一结点出发均可找到表中其他结点。

>循环单链表的操作和单链表基本一致,差别仅在于:当链表遍历时,判别当前指针p是否指向表尾结点得到终止条 件不同。在单链表中,判断条件为p!=NULL或p->next!=NULL,而循环单链表的判别条件为p!=L或p->next!=L
在某些情况下,若在循环链表中设立尾指针而不设头指针,可使一些操作简化。例如,将两个线性表合并成一个表时,仅需将第一个表的尾指针指向第二个表的第一个结点,第二个表的尾指针指向第一个表的头结点,然后释放第二个表的头结点。(“第一个结点”指头结点所指的结点)

这个操作仅需改变两个指针值即可。

LinkList  Connect(LinkList  Ta,LinkList  Tb)
{//假设Ta、Tb都是非空的单循环链表
    p = Ta-&gt;next; //①p存表头结点
    Ta-&gt;next = Tb-&gt;next-&gt;next; //②Tb表头连结Ta表尾
    delete Tb-&gt;next; //③释放Tb表头结点
    return Tb;//④修改指针
    return  Tb;
}

2、双向链表

//双向链表的存储结构
typedef struct DuLNode{
    ElemType   data;              
    struct DuLNode  *prior;  
    struct DuLNode  *next;  
}DuLNode, *DuLinkList

//在带头结点的双向循环链表L中第i个位置之前插入元素e
Status ListInsert_DuL(DuLinkList &amp;L,int i,ElemType e){
   if(!(p=GetElemP_DuL(L,i))) return ERROR;
    s= (DuLinkList)malloc(sizeof(DuLinkList)); 
    s-&gt;data=e;
   s-&gt;prior=p-&gt;prior;  p-&gt;prior-&gt;next=s;
   s-&gt;next=p;  p-&gt;prior=s;
   return OK;
}

//删除带头结点的双向循环链表L的第i个元素
Status ListDelete_DuL(DuLinkList &amp;L,int i,ElemType &amp;e){
   if(!(p=GetElemP_DuL(L,i)))     return ERROR;
   e=p-&gt;data;
   p-&gt;prior-&gt;next=p-&gt;next;
   p-&gt;next-&gt;prior=p-&gt;prior;
   free(p); 
   return OK;
}

三、线性表的应用

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!