线性表

一、线性表

顺序存储:顺序表

链式存储:单链表,双链表,循环链表---->利用指针实现

&表示c++中的引用,如果传入的变量是指针类型的变量
在c中采用指针的指针也可以同样效果。

1、顺序表

1.1、顺序表节点定义:

顺序存储类型的定义:
#define MaxSize 50//定义线性表的最大长度
typedef struct{
    ElemType data[MaxSize];//顺序表的元素
    int length;//顺序表的当前长度
}SeqList;//顺序表的类型定义
一维数组可以静态分配,也可以动态分配。
#define InitSize 100//表长度的初始定义
typedef struct{
    ElemType *data;//指示动态分配数组的指针
    int MaxSize,length;//数组的最大容量和当前个数
}SeqList

动态分配数组的C语句: L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);

顺序表所占存储空间=表长*sizeof(元素的类型) 动态分配数组的C++语句: L.data=new ElemType[InitSize];

顺序表的特点:随机访问。也就是通过首地址和元素序号可以在O(1)时间访问指定的元素。 由于顺序表的逻辑上相邻的元素物理上也相邻,所以插入和删除需要移动大量元素。

1.2、顺序表基本操作的实现(复杂度O(n))

1、插入操作
在第i个位置上插入新元素e。

bool ListInsert(SeqList &L,int i,ElemType e)
{
    if(i<1||i>L.length+1)return false;
    if(L.length>=MaxSize)return false;
    for(int j=L.length;j>=i;j--)//将第i个元素后面的元素先进行后移
        L.data[j]=L.data[j-1];
    L.data[i-1]=e;//在位置i处放入e
    L.length++;//线性表长度加1
    return true;
}

1.3、删除操作(复杂度O(n))

删除L中第i个位置的元素,将被删除的元素用引用变量e返回

bool ListDelete(SeqList &L,ElemType &e)
{
    if(i<1||i>L.length)return false;
    e=L.data[i-1];//将被删除的元素赋值给e
    for(int j=i;j<L.length;j++)//将第i个位置之后的元素前移
        L.data[j-1]=L.data[j];
    L.length--;//线性表长度减1
    return true;
}

2、单链表

单链表的节点类型定义:
typedef struct LNode{
    ElemType data;//数据域
    struct LNode *next;//指针域
}LNode,*LinkList;

 单链表是非随机存取的。因为查找某个特定的节点时,需要从表头开始遍历,依次查找

头节点和头指针:

不管带不带头节点,头指针始终指向链表的第一个节点。而带头节点链表的第一个节点,节点不存储信息的。

无论链表是否为空,头指针始终指向头节点的非空指针

2.1、采用头插法

将新节点s插入到当前链表的表头。也就是头节点后面

LinkList CreateList(LinkList &L)
{
    LNode *s;
    int x;
    L=(LinkList)malloc(sizeof(LNode));//创建头节点
    L->next=null;//初始为空链表
    scanf("%d",&x)//输入节点的值
    while(x!=999)
    {
        s=(LNode*)malloc(sizeof(LNode));创建新的节点
        s->data=x;
        s->next=L->next;
        L->next=s;
        scanf("%d",&x);
    }
    return L;
}

2.2、采用尾插法

头插法虽然建立链表简单,但是生成的链表的节点次序和输入的顺序相反。
希望输入顺序一样,可以采用尾插法。
思想:每次将新节点插入到当前链表的表尾上,所以必须要增加一个尾指针r。让它始终指向链表的尾节点。

LinkList CreateList(LinkList &L)
{
    int x;
    LNode *s,*r;//r为尾指针,s指向即将插入的新节点
    L=(LinkList)malloc(sizeof(LNode));//创建头节点。
    scanf("%d",&x);//输入节点的值
    while(x!=999)
    {
        s=(LNode*)malloc(sizeof(LNode));
        s->data=x;
        r->next=s;
        r=s;//把s赋给r,此时刚插入的新节点s成了尾指针
    }
    r->next=null;//尾指针置空
    return L;
}

2.3、按序号查找节点

在单链表中从第一个节点出发,顺着指针next域一一往下搜索。直到找到第i个节点为止。

LNode *GetElem(LinkList L,int i)
{
    int flag=1;//计数,初始为1个
    LNode *p=L->next;//头节点指针赋给p
    if(i==0)return L;//如果i=0,返回头节点
    if(i<1)return null;//如果i无效,则返回null
    while(p&&j<i)//从第1个节点开始找,查找第i个节点
    {
        p=p->next;
        j++
    }
    return p;//返回第i个节点的指针。
}
//复杂度为O(n)

2.4、按值来查找节点

从单链表中第一个节点处出发,从前往后比较表中节点数据域的值,然后返回这个节点的指针。

LNode *LocateElem(LinkList L,ElemType e)
{
    LNode *p=L->next;
    while(p!=null&&p->data!=e)//从第一个节点开始找data域为e的节点
        p=p->next;
    return p;//找到后返回该节点指针。
}

2.5、插入节点操作

插入节点时将值为x的新节点插入到单链表的第i个位置上。所以插入之前要检查位置的合法性。
然后在找到它的前驱,也就是第i-1个节点,然后进行插入操作。
所以首先调用方法GetElem(L,i-1);获取到i-1位置的指针

LNode *p=GetElem(L,i-1);
s->next=p->next;//先后连
p->next=s;//在前连
//插入操作复杂度为O(1)

2.6、删除节点操作

删除第i个节点。同理还是检查位置的合法性,然后查找第i-1个位置节点
也即是它的前驱,然后删除
所以还是调用方法GetElem(L,i-1);

LNode *p=GetElem(L,i-1);
LNode *s;
s=p->next;//让s指针指向打算删除的节点
p->nexts->next;//将s节点断开。
free(s);//释放节点空间

3、双链表

3.1、节点类型定义:

typedef struct DNode
{
    ElemType data;//数据域
    struct DNode *prior,*next;//前驱和后继指针
}DNode,*DLinkList;

3.2、双链表的插入操作:

在p节点之后插入新节点s

//核心代码
s->next=p->next;
p->next->prior=s; 
s->prior=p;
p->next=s;

3.2、双链表的删除操作

p->next=p->next->next;
p->next->next->prior=p;
free(p->next);

或者令s=p->next;
p->next=s->next;
s->next->prior=p;
free(s);

 

转载于:https://www.cnblogs.com/drq1/p/9472900.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值