线性表笔记

线性表(List):零个或多个数据元素的有限序列。

ADT 线性表(List)
Data
    数据对象为数据元素的集合,每个元素类型为DataType(用户自定义类型)。
数据元素之间的关系是一对一的关系。
Operation
    InitList(*L):初始化操作,建立一个空的线性表L
    ListEmpty(L):判断线性表是否为空,是返回TRUE,否返回FALSE
    ClearList(*L):将线性表清空
    GetElem(L, i, *e):将线性表L中第i个位置的值返回给e
    LocateElem(L, e):中L中查找与e相等的元素,查找成功,返回元素的序号,失败返回0
    ListInsert(*L, i, e):在L中第i个位置之前插入元素e
    ListDelete(*L, i, *e):删除第i个位置元素,用e返回其值
    ListLength(L): 返回L的元素个数
endADT

线性表按照存储结构可分为:线性表的顺序存储结构、线性表的链式存储结构

线性表的顺序存储结构可以通过数组来实现:

#define MAXSIZE 100    //线性表存储数据元素的空间值
typedef int ElemType;    //数据元素的类型
typedef struct{    
    ElemType data[MAXSIZE];    //存储数据元素的数组
    //另一种形式:ElemType *elem; 指向数组首地址,空间通过用户自定义分配
    int length;        //当前已有数据元素个数
}SqList;

用数组存储顺序表意味着要分配固定长度的数组空间

顺序表的随机存取结构:可以对每个位置进行存入和取出

顺序表的一些常用操作:

//取得L中位置i上的数据元素值,用e返回
//L的存储数据元素是从0开始的,故第i个位置上的元素就是数组下标i-1位置上的元素
Status GetElem(SqList L, int i, ElemType *e)
{
	if (L.length == 0 || i<1 || i>L.length)	//数据元素位置1<=i<=L.length(L的元素个数),且L中元素个数不能没有 
		return FALSE;
	*e = L.data[i-1];
	return OK;
}
//在L中第i个位置之前插入数据元素e
Status ListInsert(SqList *L, int i, ElemType e)
{
	int j;
	if (L->length == MAXSIZE)	//线性表L当前长度已满 
		return FALSE; 
	if (i<1 || i>L->length+1)	//i的位置应该为:1<=i<=L->length+1 
		return FALSE;
	if (i <= L->length)
	for (j = L->length-1; j >= i-1; j--)
		L->data[j+1] = L->data[j];
	L->data[i-1] = e;
	L->length++;
	return OK;	
}
//在L中删除第i个位置的数据元素,并用e返回其删除位置的值
Status ListDelete(SqList *L, int i, ElemType *e)
{
	int j;
	if (L->length == 0)	//线性表为空,没有数据元素删除 
		return ERROR;
	if (i < 1 || i > L->length)		//i的删除位置为:1<=i<=L->length 
		return ERROR;
	*e = L->data[i-1];
	if (i < L->length)		//i不是最后一个位置的时候,i后元素都得前移 
	for (j = i; j <= L->length-1; j++)
		L->data[j-1] = L->data[j];
	L->length--;
	return OK;
}

线性表的链式存储结构:

单链表:每个结点都有一个数据域和一个指针域。其中第一个结点的存储位置叫做头指针,最后一个结点的指针域不指向结点,为空(NULL 或 ^)。有时,会在第一个结点前附设一个结点,称为头结点。

常用头指针为链表的名字,头指针无论什么时候都不为空,可能指向随机地址。

单链表的存储结构:

typedef struct Node{
    ElemType data;        //数据域
    struct Node *next;    //指针域,存储下个结点的地址
}Node;
typedef struct Node *LinkList;    //定义链表,头指针

链表的常用操作:

//取链表的元素时,1<=i<=ListLength(i)
Status GetElem(LinkList L, int i, ElemType *e)
{
    Node *p;
    p = L->next;    //指向首元结点
    int j = 1;       
    while (j < i && p)    //循环结束,使p指向第i个位置
    {
        j++;
        p = p->next;
    }
    if (j > i || !p)    //i的位置不合法或者位置i为空(i的值超出链表长度,结点i不存在)
        return ERROR;
    *e = p->data;
    return OK;
}
Status ListInsert(LinkList *L, int i, ElemType e)
{
    int j;
    Node *p, *s;
    p = *L;    //指向头结点
    j = 1;    
    while (j < i && p)    //j<i且没有到达末尾就遍历链表,直至找到第i-1个元素
    {
        p = p->next;
        j++;
    }
    if (!p || j>i)     //提前到达末尾或者i的位置不合法
        return ERROR; 
    s = (Node *)malloc(sizeof(Node));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return OK;
}
Status ListDelete(LinkList *L, int i, ElemType *e)
{
    int j;
    Node *p, *s;
    p = *L;
    j = 1;
    while (j < i && p->next)        //找到第i-1个元素,并判断其后是否为空
    {
        p = p->next;
        j++;
    }
    if (!(p->next) || j>i)        //提前为空或者i的位置不合法
        return ERROR;   
    s = p->next;
    p->next = s->next;
    *e = s->data;
    free(s);
    return OK;
}

其操作核心在于循环部分

链表的整表创建可以用头插法和尾插法。整表的删除通过两个指针循环操作。

void CreateListHead(LinkList *L, int n)
{
	Node *p;
	int i;
	*L = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL;    //建立一个带有头结点的空链表
	srand(time(0));
	for (i = 0; i < n; i++)
	{
		p = (Node *)malloc(sizeof(Node));
		p->data = rand()%100+1;
		p->next = (*L)->next;
		(*L)->next = p;
	}
}
void CreateListTail(LinkList *L, int n)
{
	Node *p, *s;	//p为了生成结点,s为了指向末尾结点 
	int i;
	*L = (LinkList)malloc(sizeof(Node));
	s = *L;
	srand(time(0));
	for (i = 0; i < n; i++)
	{
		p = (Node *)malloc(sizeof(Node));
		p->data = rand()%100+1;
		s->next = p;
		s = p; 
	}
	s->next = NULL;
}
Status ClearList(LinkList *L)
{
	Node *p, *q;
	p = (*L)->next;		//p指向首元结点
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
	return OK;
}

除了顺序表和链表外,还有静态链表、循环链表、双向链表等。

静态链表:通过存储数组下标来描述逻辑结构。其中未被使用的数组元素称为备用链表。其中下标为0的元素就存放备用链表(未被使用过)的第一个结点的下标,而最后一个元素就存放第一个有数值的元素的下标,没有就存0(相当于头结点)。其中数据元素存放下一个数据元素的下标,最后一个有数据的元素存放下标0

静态链表的存储结构:

#define MAXSIZE 100
typedef struct{
    ElemType data;
    int cur;
}Component, StaticLinkList[MAXSIZE];

循环链表:将单链表中的终端结点的指针域改为指向头结点,形成头尾相接。 循环链表的终端结点可以用尾指针rear来指向,这样查找头结点和终端结点的时间复杂度都是O(1)。

双向链表:在单链表的基础上,再设置一个指向前驱结点的指针域。另外,双向链表也可以是循环表。

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

线性表的无序合并:通过遍历表LB中元素,查找LA是否存在相同元素,不存在则插入。

线性表的有序合并:前提两个线性表都是有序的。通过两个指针分别指向表头,不断指向后继元素,按照指定次序比较,只要到达一个线性表末尾就停止,将另一个线性表的剩余元素都插入。顺序表和链表的有序合并不同,顺序表需要开辟新的空间,链表不需要。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值