线性表
1.顺序表示
1.1 定义
数组从0开始,顺序表从1开始
#define MaxSize 100 //最大长度
typedef struct{
ElemType *date; //指向数据元素的基地址
int length; //线性表的当前长度
}SqList;
bool InitList_Sq(SqList &L)
{
L.data = new ElemType[MaxSize];
if(!L.data)
exit(OVERFLOW);
L.length = 0;
return true;
}
1.2 基本操作
1.2.1 查找
注意:是返回其位序
//在线性表L中查找值为e的数据元素,并返回其位序
int LocateElem_Sq(SqList L, ElemType e)
{
for(int i = 0; i < L.length; i++)
{
if(L.date[i] == e)
return i+1;
}
return 0;
}
算法平均时间复杂度为O(n)。
1.2.2 插入
//在线性表L中第i个位置插入元素e
//判断插入位置i是否合法
//判断顺序表的存储空间是否已满
//将第n至第i位元素依次向后移动一个位置
//将要插入的元素e放入第i个位置
//表长加1,插入成功返回true
//在线性表L中第i个位置插入元素e
bool ListInsert_Sq(SqList &L, int i, ElemType e)
{
//判断插入位置i是否合法
if( i<1 || i>L.length+1 )
return false;
//判断顺序表的存储空间是否已满
if( L.length == MaxSize )
return false;
//将第n至第i位元素依次向后移动一个位置
for(int j = L.length; j>=i; j--)
L.date[j] = L.date[j-1];
//将要插入的元素e放入第i个位置
L.date[i] = e;
//表长加1,插入成功返回true
L.length++;
return true;
}
算法平均时间复杂度为O(n)------平均移动次数。
1.2.3 删除
//删除第i个节点,将被删除元素赋值给引用变量e
//判断删除元素位置i是否合法
//将欲删除元素保留在e中
//将第i+1至n位的元素依次向前移动一个位置
//表长+1,删除成功返回true
//删除第i个节点,将被删除元素赋值给引用变量e
bool ListDelete_Sq(SqList &L, int i, ElemType &e)
{
//判断删除元素位置i是否合法
if(i < 1 || i > L.length)
return false;
//将欲删除元素保留在e中
e = L.date[i]
//将第i+1至n位的元素依次向前移动一个位置
for(int j = i; j < L.length; j++)
L.date[j-1] = L.date[j];
//表长-1,删除成功返回true
L.length--;
return true;
}
算法平均时间复杂度为O(n)------平均移动次数。
顺序表的空间复杂度S(n)=O(1),没有占用辅助空间。
1.3 题解
1.3.1选择
001.顺序表的插入算法中,当n个空间已满时,可再申请增加分配m个空间=需要申请n+m个
连续的存储空间。
2.链式表示
单向链表:只有一个指向后继节点的指针域。
双向链表:有两个指针域,一个指向前驱,一个指向后继。
循环链表:首尾相接
头指针→头结点→首元结点
p永远是头结点p=L→next;
如何表示空表?
答:头结点指针域为空。
在链表中设置头结点有什么好处?
答:1.便于首元结点的处理;
2.便于空表和非空表的统一处理。
头结点的数据域内装的是什么?
答:头结点数据域可以为空,也可以存放线性表长度等附加信息
但是此节点不能计入链表长度值。
2.1 单链表
2.1.1 定义
单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名。
若头指针名为L,则把链表称为L。
typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域
}LNode, *LinkList;
//初始化,构造一个空表
bool Init_List(LinkList &L)
{
//生成新结点做头结点,头指针指向头结点
L = new LNode;
//头结点的指针域置为空
L->next = NULL;
return true;
}
LNode *p = LinkList p;
2.1.2 查找
//根据指定数据获取数据所在的位置
LNode *LocateElem_List(LinkList &L, ElemType e)
{
//从第一个节点起,依次和e做比较
LNode *p = L->next;
while(p != NULL && p->data != e)
{
p = p->next;
}
//如果找到一个和e相等的数据元素,返回其在链表中的位置;否则返回NULL
return p;
}
查找算法时间复杂度为O(n)
2.1.3 插入
顺序不能乱:①s→next=p→next;②p→next=s
//将值为x的新节点插入到单链表的第i个位置上
bool Insert_List(LinkList &L, int i, ElemType x)
{
LNode *p = L;
int j = 0;
//找到 a(i-1)的存储位置p
while(p && j < i-1)
{
p = p->next;
j++;
}
//检查插入位置的合法性
if(!p || j > i-1)
return false;
//生成一个新结点*s
s = new LNode;
//将新结点*s的数据域置为x
s->data = x;
//新结点*s的指针域指向结点a(i)
s->next = p->next;
//令结点a(i-1)的指针域指向新结点*s
p->next = s;
return true;
}
查找算法时间复杂度为O(n)
前插操作同理后在交换数据域的值
2.1.4 删除
//删除第i个结点,把删除结点的值保存在e中
bool Delete_List(LinkList &L, int i, ElemType &e)
{
LNode *p = L;
int j = 0;
//找到a(i-1)存储位置p
while(p && j < i-1)
{
p = p->next;
j++;
}
//临时保存结点a(i)的地址在q中,以备释放
LNode *q = p->next;
//令p->next指向a(i)的后继结点
p->next = q->next;
//将a(i)的值保留在e中
e = q->data;
//释放a(i)的空间
delete q;
return true;
}
查找算法时间复杂度为O(n)
2.1.5 单链表的建立
前插法:倒放
尾插法:正放
2.2 双向链表
2.2.1 定义
typedef struct DNode{
ElemType data; //数据域
struct DNode *prior; //前驱指针
struct DNode *next; //后继指针
}DNode, *DLinkList;
双向链表的按值查找和按序查找与单链表相同;
插入和删除不同,需要对前驱指针做出修改。
2.2.2 插入
//将值为x的新节点插入到双向链表的第i个位置上
bool Insert_DList(DLinkList &L, int i, ElemType e)
{
//找到 a(i)的存储位置p
//生成一个新结点*s
//将新结点*s的数据域置为x
//顺序不能乱,先赋值新结点*s的指针
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
}
2.2.3 删除
//删除第i个结点,把删除结点的值保存在e中
bool Delete_DList(DLinkList &L, int i, ElemType &e)
{
//找到 a(i)的存储位置p--today
//yesterday的后继指针指向tomorrow
p->prior->next = p->next;
//tomorrow的前驱指针指向yesterday
p->next->prior = p->prior;
delete p;
}
2.3 循环链表
循环链表可以从表中任意位置开始遍历。
本文详细介绍了线性表的顺序表示和链式表示,包括顺序表的定义、查找、插入和删除操作,以及链表的单链表、双向链表和循环链表的特性。在顺序表中,查找、插入和删除的时间复杂度平均为O(n),而在链表中,这些操作各有特点,如单链表插入需考虑前后节点关系。
444

被折叠的 条评论
为什么被折叠?



