【数据结构】2.线性表

线性表的定义和基本操作

线性表的定义

线性表:具有相同数据类型的数据元素的有限序列。

表头元素表尾元素(直接)前驱(直接)后继

特点:

  • 元素个数有限;
  • 每个元素数据类型相同,占用存储空间相同;
  • 线性表是逻辑结构,而顺序表和链表是存储结构
  • 随机访存,通过首地址和序号可以用时间 O ( 1 ) O(1) O(1)找到元素;
  • 存储密度高,因为每个结点只存储数据元素;
  • 逻辑上相邻的元素物理上也相邻,插入和删除需要时间 O ( n ) O(n) O(n)

顺序表

顺序表的定义

静态分配存储空间

#def MaxSize 100

typedef struct SqList {
    int data[MaxSize];
    int length;
}SqList;

动态分配存储空间

#def InitSize 100

typedef struct {
    int* data;
    int maxSize, length;
}SeqList;

SeqList L;
L.data = new int[InitSize]

顺序表的基本操作

注意顺序表的元素序号从1开始,而实现时使用的数组下标从0开始。

插入
//将元素e插入到i位置,返回是否插入成功
bool SqInsert(SqList& L, int i, int e) 
{
    //判断i的范围是否合法
    if (i<1 || i>L.length + 1)
        return false;
    //判断存储空间是否已满
    if (L.length >= MaxSize)
        return false;
    //将i号及之后的元素后移
    for (int j = L.length; j >= i; j--)
        L.data[j] = L.data[j - 1];
    //将元素i设置为e
    L.data[i - 1] = e;
    L.length++;
    return true;
}
删除
//删除第i个元素,用引用变量e返回
bool SqDelete(SqList& L, int i, int& e) 
{
    //判断i的范围是否合法
    if (i<1 || i>L.length)
        return false;
    e = L.data[i - 1];
    //将i个元素之后的所有元素前移
    for (int j = i; j < L.length; j++)
        L.data[j - 1] = L.data[j];
    L.length--;
    return true;
}
按值查找(定位某个元素)
//查找值为e的元素序号
int SqLocate(SqList L, int e) 
{
    int i;
    for (i = 0; i < L.length; i++)
        if (L.data[i] == e)
            return i + 1;
    return 0;
}

链表

单链表

定义

数据域存放数据元素,指针域存放后继结点的地址。

typedef struct LNode {
    int data;
    struct LNode* next;
}LNode, * LinkList;
头插法

单链表头插法

//头插法
LinkList ListHeadInsert(LinkList &L) 
{
    LNode* s;
    int x;
    //L = (LinkList)malloc(sizeof(LNode));
    L = new LNode;
    L->next = NULL;
    cin >> x;
    while (x != 9999) {
        s = (LinkList)malloc(sizeof(LNode));
        s->data = x;
        s->next = L->next;
        L->next = s;
        cin >> x;
    }
    return L;
}
尾插法

单链表尾插法

//尾插法
//1.建立头指针、尾指针,分配头结点;
//2.循环分配新结点,插到最后(加一根线);
//3.尾结点next置为NULL;
LinkList ListTailInsert(LinkList& L) 
{
    //L = (LinkList)malloc(sizeof(LNode));
    L = new LNode;
    LNode* s;
    LNode* t = L;
    int x;
    L->next = NULL;
    cin >> x;
    while (x != 9999) {
        //s = (LinkList)malloc(sizeof(LNode));
        s = new LNode;
        s->data = x;
        t->next = s;
        t = s;
        cin >> x;
    }
    t->next = NULL;
    return L;
}
按序号查找结点
// 按序号查找结点
LNode* LGetElem(LinkList L, int i) 
{
    LNode* r = L;
    int j = 0;//头结点视为0号结点
    while (r != NULL && j < i) {
        r = r->next;
        j++;
    }
    return r;
}
按值查找结点
//按值查找结点
LNode* LLocateElem(LinkList L, int e) 
{
    LNode* r = L;
    while (r != NULL && r->data != e)
        r = r->next;
    return r;
}
插入结点

单链表插入结点

//插入元素e到pos位置 
bool LPositionInsert(LinkList& L, int e, int pos) 
{
    LNode* priorNode = LGetElem(L, pos - 1);
    if (priorNode == NULL)
        return false;
    LNode* newNode = new LNode;
    newNode->data = e;
    newNode->next = priorNode->next;
    priorNode->next = newNode;
    return true;
}
删除结点

单链表删除结点

//删除pos位置的结点,并返回结点数据元素
int LPositionDelete(LinkList& L, int pos) 
{
    LNode* priorNode = LGetElem(L, pos - 1);
    if (priorNode == NULL || priorNode->next == NULL)
        return 9999;
    LNode* delNode = priorNode->next;
    int r = delNode->data;
    priorNode->next = delNode->next;
    delete delNode;
    return r;
}
求表长
//求链表长度
int GetLength(LinkList L) 
{
    int length = 0;
    LNode* p = L->next;
    while (p != NULL) {
        p = p->next;
        length++;
    }
    return length;
}

双链表

相比单链表,访问、插入、删除前驱结点的复杂度均为 O ( 1 ) O(1) O(1)(单链表为 O ( n ) O(n) O(n))。

定义
typedef struct DNode {
	int data;
	struct DNode* prior, * next;
}DNode, * DLinkList;
插入结点

双链表插入结点

//插入元素e到pos位置 
bool DPositionInsert(DLinkList& DL, int e, int pos) 
{
	DNode* priorNode = DGetElem(DL, pos - 1);
	if (priorNode == NULL)
		return false;
	DNode* newNode = new DNode;

	//如图所示,四步操作必须按顺序进行
	newNode->data = e;
	newNode->next = priorNode->next;
	if (priorNode->next != NULL)
		newNode->next->prior = newNode;
	newNode->prior = priorNode;
	priorNode->next = newNode;

	return true;
}
删除节点

双链表删除结点

//删除pos位置的结点,并返回结点数据
int DPositionDelete(DLinkList& DL, int pos) 
{
	DNode* priorNode = DGetElem(DL, pos - 1);
	if (priorNode == NULL || priorNode->next == NULL)
		return 9999;
	DNode* delNode = priorNode->next;
	int r = delNode->data;

	if (delNode->next != NULL)
		delNode->next->prior = priorNode;
	priorNode->next = delNode->next;

	delete delNode;
	return r;
}

循环链表

循环单链表

与单链表相比,表的尾结点的尾指针指向头结点。

尾指针:提高在表尾插入元素操作效率

时间复杂度在表头插入元素在表尾插入元素
头指针 O ( 1 ) O(1) O(1) O ( n ) O(n) O(n)
尾指针 O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1)
循环双链表

与双链表相比,表的尾结点的尾指针指向头结点;当表为空表时,头结点的头尾指针都指向头结点。

静态链表

借助数组实现的链表

特点:

  • 与顺序表一样需要预先分配存储空间;
  • n e x t = = 1 next==1 next==1为表结束标志;
  • 插入、删除操作只需要移动指针不需要修改元素;
#define MaxSize 100

typedef struct{
    int data;
    int next
}SLinkList[maxSize];
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值