- 线性表的定义和特点
1.1 引入
- 线性表、栈、队列、串和数组都是线性结构。
- 线性结构的特点:除第一个元素无直接前驱、最后一个元素无直接后继之外,其他每个数据元素都有一个前驱和后继。
1.2 线性表 - 定义:由n个数据特性相同的元素构成的有限序列。
- 当线性表中的个数n(线性表的长度)为0时称之为空表。
- 特点:
(1) 存在唯一的一个被称作“ 第一个" 的数据元素;
(2) 存在唯一的一个被称作“ 最后一个" 的数据元素;
(3) 除第一个之外, 结构中的每个数据元素均只有一个前驱;
(4) 除最后一个之外,结构中的每个数据元素均只有一个后继。 - 线性表中的关系是一对一的。
- 案例引入
2.1 一元多项式的运算
顺序结构线性表
2.2 稀疏多项式的运算
链式存储结构
补充的是:一个指针占8个字节。
线性表中数据元素的类型可以为简单类型,也可以为复杂类型。
许多实际应用问题所涉的基本操作有很大相似性,不应为每个具体应用单独编写一个程序。
从具体应用中抽象出共性的逻辑结构和基本操作(抽象数据类型),然后实现其存储结构和基本操作。 - 线性表的类型定义
- 线性表抽象数据类型List
= 线性表中元素的逻辑结构 + 基本运算定义
[图片]
1)InitList (&L)
操作结果:构造一个空的线性表L。
2)DestroyList(&L)
初始条件:线性表L已存在。
操作结果:销毁线性表L。
3)ClearList (&L)
初始条件:线性表L已存在。
操作结果:将L重置为空表。
4)ListEmpty(L)
初始条件:线性表L已存在。
操作结果:若L为空表, 则返回true, 否则返回false。
5)ListLength(L)
初始条件:线性表L已存在。
操作结果:返回L中数据元素个数
6)GetElem(L,i,&e)
初始条件:线性表L已存在, 且1≤i≤ListLength(L)。
操作结果:用e返回L中第i个数据元素的值。
7)LocateElem(L,e)
初始条件:线性表L已存在。
操作结果:返回L中第1个值与e相同的元素在L中的位置。若这样的数据元素不存在,则返回值为0。
8)PriorElem(L,cur_e,&pre_e)
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回其前驱,否则操作失败,pre_e无定义。
9)NextElem(L,cur_e,&next_e)
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回其后继,否则操作失败,next_e无定义。
10)ListInsert(&L,i,e)
初始条件: 线性表L已存在,且1 ≤i≤ ListLength (L) +1。
操作结果:在L中第i个位置之前插入新的数据元素e, L的长度加1。
11)ListDelete(&L,i)
初始条件:线性表L 已存在且非空,且1≤i≤ ListLength(L)。
操作结果:删除L的第i个数据元素,L的长度减1。
12)TraverseList(L)
初始条件:线性表L已存在。
操作结果:对线性表L进行遍历,在遍历过程中对L的每个结点访问一次。
```cpp
#include<bits/stdc++.h>
using namespace std;
#define MAXSIZE 100
#define ERROR 0
const int OVERFLOW = -1; // 溢出错误码
const int OK = 0; // 操作成功码
typedef struct { //定义顺序表
int *elem;
int length;
}List;
int n, m;
int e;
int pre_e;
char st = 'A';
bool InitList(List &L) //创建顺序表
{
L.elem = new int[MAXSIZE];
if(!L.elem) exit(OVERFLOW); //存储分配失败退出
L.length = 0;
return OK;
}
void DestroyList(List &L) {//摧毁线性表
delete[] L.elem;
L.elem = nullptr;
L.length = 0;
}
void ClearList(List &L) {//清空线性表
L.length = 0;
}
bool isEmpty(const List& L) {//判断是否为空
return L.length == 0;
}
int ListLength(List L) //求顺序表的长度
{
return L.length;
}
int GetElem(List L, int i, int &e) //求顺序表的第i个元素,并以e返回
{
e = L.elem[i - 1];
return e;
}
int LocateElem(List L, int e) //判断List里有没有e这个元素,并返回位置
{
int i;
for (i = 0; i < L.length; i++)
if (e == L.elem[i])
return i + 1; // 返回位置(从1开始计数)
return 0; // 若找不到匹配的元素,则返回0
}
void ListInsert(List &L, int e) //将e插入到List的最后
{
L.elem[L.length] = e;
L.length++;
}
bool PriorElem(List L, int cur_e, int* pre_e) // 判断cur_e是否是L的数据元素,且不是第一个,返回其前驱pre_e
{
int i;
for (i = 1; i < L.length; i++)
if (cur_e == L.elem[i])
{
*pre_e = L.elem[i - 1]; // 将前驱赋值给pre_e
return true; // 操作成功
}
return false; // 若找不到匹配的元素或cur_e是第一个元素,则操作失败
}
bool NextElem(List L, int cur_e, int* next_e) // 判断cur_e是否是L的数据元素,且不是最后一个,返回其后继next_e
{
int i;
for (i = 0; i < L.length - 1; i++)
if (cur_e == L.elem[i])
{
*next_e = L.elem[i + 1]; // 将后继赋值给next_e
return true; // 操作成功
}
return false; // 若找不到匹配的元素或cur_e是最后一个元素,则操作失败
}
void ListDelete(List &L, int i) // 删除L的第i个元素,L的长度-1
{
if (i < 0 || i >= L.length) {
// 索引越界,无法删除元素
return;
}
for (int j = i; j < L.length - 1; j++) {
L.elem[j] = L.elem[j + 1];
}
L.length--;
}
void ListOutput(List L) //输出List
{
int i;
for (i = 0; i < L.length; i++)
cout << L.elem[i] << " ";
cout << endl;
}
void ListTraverse(List &L) // 遍历线性表L,访问每个节点一次
{
for (int i = 0; i < L.length; i++) {
// 在这里可以对节点进行操作,例如输出节点的值
cout << L.elem[i] << " ";
}
cout << endl;
}
int main() {
List LA;
InitList(LA);
ClearList(LA);
isEmpty(LA);
ListInsert(LA, 1);
ListInsert(LA, 2);
ListInsert(LA, 2);
ListInsert(LA, 3);
cout<<"查看当前线性表:"<<endl;
ListOutput(LA);
cout<<"线性表LA的长度是:";
cout<<ListLength(LA)<<endl;
cout << "第3个元素的值是:" <<GetElem(LA,3,e)<< endl;
cout<<"第一个与e相同的元素的位置是:"<<LocateElem(LA,e)<<endl;
int cur_e = 2;
int pre_e; // 用于存储前驱元素的值
int next_e;
bool success = PriorElem(LA, cur_e, &pre_e); // 调用PriorElem函数
if (success) {
cout << "前驱元素是:" << pre_e << endl;
} else {
cout << "操作失败" << endl;
}
bool succ = NextElem(LA, cur_e, &next_e);
if (succ) {
cout << "后继元素是:" << next_e << endl;
} else {
cout << "操作失败" << endl;
}
int to_delete;
cout << "请输入要删除的元素的值:" << endl;
cin >> to_delete;
ListDelete(LA,to_delete);
cout << "此时的线性表为: "<<endl;
ListOutput(LA);
cout<<"遍历当前线性表的结果是:"<<endl;
ListTraverse(LA);
DestroyList(LA); //销毁
return 0;
}
```cpp
#include<iostream>
#include<string.h>
#define MAXSIZE 100
#define OVERFLOW -2
#define OK 1
#define ERROR 0
typedef int Status;
using namespace std;
typedef struct
{
int *elem;//指向数据元素的基地址
int length; //线性表当前长度
}SqList;
//初始化
Status InitList(SqList &L)
{
L.elem=new int[MAXSIZE];
if(!L.elem) exit(OVERFLOW);
L.length=0;
return OK;
}
//创建顺序表
Status ListCreat(SqList &L,int j,int e)
{
//合法性判断j<0或j>MAXSIZE
if(j<0||j>MAXSIZE) return ERROR;
if(L.length==MAXSIZE) return OVERFLOW;
L.elem[j]=e;
//更新长度
L.length++;
return OK;
}
//按值查找
Status LocateElem(SqList L,int f)
{
int i;
for(i=0;i<L.length;i++)
{
if(L.elem[i]==f)
{
cout<<L.elem[i]<<"的位置是:"<<i+1<<endl;
return OK;
}
}
return ERROR;
}
//按位查找
Status GetElem(SqList L,int i,int &e)
{
if(i<1||i>L.length) return ERROR;
e=L.elem[i-1];
return OK;
}
//插入
Status ListInsert_Sq(SqList &L,int i,int e)
{
int j;
if((i<1)||(i>L.length+1)) return ERROR;
if(L.length==MAXSIZE) return ERROR;
for(j=L.length-1;j>=i-1;j--)
{
L.elem[j+1]=L.elem[j];
}
L.elem[i-1]=e;
++L.length;
return OK;
}
//按位删除操作
Status ListDelete_Sq(SqList &L,int i)
{
int j;
if((i<1)||(i>L.length)) return ERROR;
for(j=i;j<=L.length-1;j++)
{
L.elem[j-1]=L.elem[j];
}
--L.length;
return OK;
}
//求表长
Status ListLength(SqList &L)
{
if(L.length==0) return 0;
return L.length;
}
//清空
void ClearList(SqList &L)
{
L.length=0;
}
//判空表
Status ListEmpty(SqList &L)
{
if(L.length==0) return 1;
return 0;
}
//重复元素位置的判断
int LocateElem_s(SqList &L, int e) //判断List里有没有e这个元素,并返回位置
{
int i;
for (i = 0; i < L.length; i++)
if (e == L.elem[i])
return i + 1; // 返回位置(从1开始计数)
return 0; // 若找不到匹配的元素,则返回0
}
//销毁顺序表
void DestroyList(SqList &L)
{
int a;
cout<<"是否销毁顺序表(1/0):"<<endl;
cin>>a;
if(a==1)
{
L.length=0;
delete[] L.elem;
cout<<"顺序表已销毁"<<endl;
}
}
bool PriorElem(SqList &L, int cur_e, int* pre_e) // 判断cur_e是否是L的数据元素,且不是第一个,返回其前驱pre_e
{
int i;
for (i = 1; i < L.length; i++)
if (cur_e == L.elem[i])
{
*pre_e = L.elem[i - 1]; // 将前驱赋值给pre_e
return true; // 操作成功
}
return false; // 若找不到匹配的元素或cur_e是第一个元素,则操作失败
}
bool NextElem(SqList &L, int cur_e, int* next_e) // 判断cur_e是否是L的数据元素,且不是最后一个,返回其后继next_e
{
int i;
for (i = 0; i < L.length - 1; i++)
if (cur_e == L.elem[i])
{
*next_e = L.elem[i + 1]; // 将后继赋值给next_e
return true; // 操作成功
}
return false; // 若找不到匹配的元素或cur_e是最后一个元素,则操作失败
}
int main()
{
int i,f,j,k,m,n;
int e,g,h,s;
SqList L;
//初始化
InitList(L);
cout<<"请输入数列总数:";
cin>>n;
cout<<"请依次输入序列的值:"<<endl;
//根据用户输入人数及信息创建顺序表
for(i=0;i<n;i++)
{
cin>>e;
ListCreat(L,i,e);
}
cout<<"目前表中有"<<L.length<<"个元素如下:"<<endl;
for(i=0;i<n;i++)
{
cout<<L.elem[i]<<endl;
}
//按值查找
cout<<"请输入元素的值:";
cin>>f;
LocateElem(L,f);
//按位置查找
cout<<"请输入待查元素的序号:";
cin>>j;
GetElem(L,j,g);
cout<<"查找到的元素是:"<<g<<endl;
//插入
cout<<"插入操作——请输入元素的位置和元素:"<<endl;
cin>>k>>h;
ListInsert_Sq(L,k,h);
cout<<"插入操作后的所有元素如下:"<<endl;
for(i=0;i<L.length;i++)
{
cout<<L.elem[i]<<endl;
}
//求第一个与某元素相同的元素
cout<<"输入重复元素的位置:"<<endl;
cin>>s;
cout<<"第一个与"<<s<<"相同的元素的位置是:"<<LocateElem_s(L,s)<<endl;
//求前驱后继
int cur_e;
cout<<"请输入要求前驱和后继的元素:"<<endl;
cin>>cur_e;
int pre_e; // 用于存储前驱元素的值
int next_e;
bool success = PriorElem(L, cur_e, &pre_e); // 调用PriorElem函数
if (success) {
cout << "ta的前驱元素是:" << pre_e << endl;
} else {
cout << "求前驱操作失败" << endl;
}
bool succ = NextElem(L, cur_e, &next_e);
if (succ) {
cout << "ta的后继元素是:" << next_e << endl;
} else {
cout << "求后继操作失败" << endl;
}
//按位删除操作
cout<<"请输入删除的位序:";
cin>>m;
ListDelete_Sq(L,m);
cout<<"按位删除操作后的所有元素的信息如下:"<<endl;
for(i=0;i<L.length;i++)
{
cout<<L.elem[i]<<endl;
}
//求表长
int len=ListLength(L);
cout<<"顺序表的表长"<<len;
//清空
ClearList(L);
//判空表
if(ListEmpty(L))
cout<<"这是一个空表。";
else
cout<<"这不是空表。";
//销毁顺序表
DestroyList(L);
return OK;
}
- 求前驱的单独函数:
#include<bits/stdc++.h>
using namespace std;
#define MAXSIZE 100
const int OVERFLOW = -1; // 溢出错误码
const int OK = 0; // 操作成功码
typedef struct { //定义顺序表
int *elem;
int length;
}List;
char st = 'A';
bool InitList(List &L) //创建顺序表
{
L.elem = new int[MAXSIZE];
if(!L.elem) exit(OVERFLOW); //存储分配失败退出
L.length = 0;
return OK;
}
void ListInsert(List &L, int e) //将e插入到List的最后
{
L.elem[L.length] = e;
L.length++;
}
bool PriorElem(List L, int cur_e, int* pre_e) // 判断cur_e是否是L的数据元素,且不是第一个,返回其前驱pre_e
{
int i;
for (i = 1; i < L.length; i++)
if (cur_e == L.elem[i])
{
*pre_e = L.elem[i - 1]; // 将前驱赋值给pre_e
return true; // 操作成功
}
return false; // 若找不到匹配的元素或cur_e是第一个元素,则操作失败
}
bool NextElem(List L, int cur_e, int* next_e) // 判断cur_e是否是L的数据元素,且不是最后一个,返回其后继next_e
{
int i;
for (i = 0; i < L.length - 1; i++)
if (cur_e == L.elem[i])
{
*next_e = L.elem[i + 1]; // 将后继赋值给next_e
return true; // 操作成功
}
return false; // 若找不到匹配的元素或cur_e是最后一个元素,则操作失败
}
void ListOutput(List L) //输出List
{
int i;
for (i = 0; i < L.length; i++)
cout << L.elem[i] << " ";
cout << endl;
}
int main() {
List LA;
InitList(LA);
ListInsert(LA, 1);
ListInsert(LA, 2);
ListInsert(LA, 3);
ListInsert(LA, 4);
cout<<"线性表为:"<<endl;
ListOutput(LA);
int cur_e;
cout<<"请输入在线性表中的一个元素:"<<endl;
cin>>cur_e;
int pre_e; // 用于存储前驱元素的值
int next_e;
bool success = PriorElem(LA, cur_e, &pre_e); // 调用PriorElem函数
if (success) {
cout << cur_e<<"的前驱元素是:" << pre_e << endl;
} else {
cout << "求前驱操作失败" << endl;
}
bool succ = NextElem(LA, cur_e, &next_e);
if (succ) {
cout<<cur_e << "的后继元素是:" << next_e << endl;
} else {
cout << "求后继操作失败" << endl;
}
return 0;
}
- 单链表的定义和表示
- 单链表中指针的常用操作:
- 结点的赋值:
LNode *p;
p=new LNode;
p->data=20;//数据域
p->next=null;//指针域 - 指针的指向:(把等号读作指向更方便理解,特别注意在同一个链时不要把中间链弄丢)
q=p;//q和p指向同一地址
q=p->next;//q指向p的下一个地址
q->next=p;q的下一个元素和p指向同一个元素 - 关于指针类型的定义:
char *p;//指针的类型是一致的,只是指针指向元素的类型不一致
int *q;
LNode *l;//结点类型的指针
- 结点的赋值:
- 防止链丢失的重要顺序:
[图片] - 关于单链表中的循环:
- 初始化:
Linklist L;
p=L->next;//p指向第一个元素
p=l;//p指向第0个元素 - 循环体的执行条件:
while(p!=null) while§//处理到第n号元素
while(p->next)处理到第n-1号元素
- 初始化:
- 单链表的相关操作:
#include<bits/stdc++.h>
#define OVERFLOW -2
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
using namespace std;
//描述结构指针
typedef struct LNode
{
ElemType data;//结点的数据域
struct LNode *next;//指针域
}LNode,*LinkList;
//初始化
Status InitList(LinkList &L)
{
L=new LNode;
L->next=nullptr;
return OK;
}
//输出封装
void outputList(LinkList L)
{
LNode *p=L->next;
while (p)
{
cout<<p->data<<" ";
p=p->next;
}
cout << endl;
}
//按值查找
Status GetElem(LinkList L,int i,ElemType &e)
{
LNode *p=L->next;
int j=1;//初始化p指向首元结点,计数器j的初值赋值为1
while(p&&j<i)
{
p=p->next;
++j;
}
if(!p||i<1||i>j) return ERROR;//i的值太大或者太小
e=p->data;
return OK;
}
//按地址查找
int LocateElem(LinkList L,ElemType e)
{
LNode *p=L->next;//p指向首元结点
int i=1;
while(p&&p->data!=e)
{
p=p->next;
i++;
}
return i;
}
//插入
Status ListInsert(LinkList &L,int i,ElemType e)
{
LNode *p = L;
int j = 0;
while(p&&j<i-1)
{
p=p->next;
++j;
}
if(!p||i<1) return ERROR;
LNode *s=new LNode;
s->data=e;
s->next=p->next;
p->next=s;
return OK;
}
//单链表的后插操作
bool InsertNode(LNode *p,ElemType e)
{
if(p==NULL) return false;
// LNode *s=(LNode *)malloc(sizeof(LNode));
LNode *s=new LNode;
if(s==NULL) return false;
s->data=e;
s->next=p->next;
p->next=s;
return true;
}
//单链表的前插操作
bool InsertPriortNode(LNode *p,ElemType e)
{
if(p==NULL) return false;
// LNode *s=(LNode *)malloc(sizeof(LNode));
LNode *s=new LNode;
if(s==NULL) return false;
s->data=e;
s->next=p->next;
p->next=s;
s->data=p->data;//将p中的元素复制到s中
p->data=e;//p中的元素覆盖为e
return true;
}
//求表长
int ListLength(LNode *L)
{
LNode *p=L->next;
int sum=0;
while(p)
{
sum++;
p=p->next;
}
return sum;
}
//删除单链表中的元素
Status ListDelete(LinkList &L,int i)
{
LNode *p=L;
int j=0;
while((p->next)&&(j<i-1))
{
p=p->next;
++j;
}
if(!(p->next)||(i<1)) return ERROR;
LNode *q=p->next;
p->next=q->next;
delete q;
return OK;
}
//销毁单链表
Status DestroyList(LinkList &L)
{
LinkList p = L;
while (p != nullptr)
{
L = p->next;
delete p;
p = L;
}
return OK;
}
int main()
{
LinkList L;
//初始化
InitList(L);
//输入单链表
int n;
cout<<"请输入单链表的长度:"<<endl;
cin>>n;
for(int i=1;i<=n;i++)
{
int e;
cout << "请输入第" << i << "个元素:";
cin >> e;
if (ListInsert(L, i, e) == ERROR)
{
cout << "插入失败!" << endl;
break;
}
}
//取值
int a,b;
cout<<"请输入要查找的元素的序号:";
cin>>a;
GetElem(L,a,b);
cout<<"该序号的元素是:"<<b<<endl; // 修改这里,将n改为b
//按值查找
int j;
cout<<"请输入要查找的元素的值:";
cin>>j;
// LNode *result=LocateElem(L,j);
cout<<"元素"<<j<<"的序号为:"<< LocateElem(L,j)<<endl;
// if(result)
// cout<<"找到元素值为"<<j<<"的节点"<<endl;
// else
// cout<<"未找到元素值为"<<j<<"的节点"<<endl;
//插入
int g,h;
cout<<"请输入要插入的位置和值:"<<endl;
cin>>g>>h;
ListInsert(L,g,h);
outputList(L);
//前插
int r,k;
cout<<"请输入要前插的元素的位置和值;"<<endl;
cin>>r>>k;
LNode *p =L;
for (int i = 0; i < r-1 && p != NULL; i++) {
p = p->next;
}
if (p == NULL) {
cout << "插入位置不合法" << endl;
return 0;
}
if (InsertPriortNode(p, k)) {
cout << "前插插入成功" << endl;
outputList(L);
} else {
cout << "前插插入失败" << endl;
}
//后插
int r_h,k_h;
cout<<"请输入要后插的元素的位置和值;"<<endl;
cin>>r_h>>k_h;
LNode *o = L;
for (int q = 0; q < r-1 && o != NULL; q++) {
o = o->next;
}
if (o == NULL) {
cout << "插入位置不合法" << endl;
return 0;
}
if (InsertNode(o->next, k_h)) {
cout << "后插插入成功" << endl;
outputList(L);
} else {
cout << "后插插入失败" << endl;
}
//输出查看
outputList(L);
//求表长
cout<<"表长为:"<<ListLength(L)<<endl;
//删除
int d;
cout<<"输入要删除的元素位置:"<<endl;
cin>>d;
ListDelete(L,d);
cout<<"此时的线性表为:"<<endl;
outputList(L);
//销毁单链表
DestroyList(L);
if (DestroyList(L)) {
cout << "链表已经被摧毁" << endl;
} else {
cout << "链表尚未被摧毁" << endl;
}
}
注:前插的操作存在一点问题。
4.1 求前驱求后继
//求前驱
Status PriorElem(LinkList L,ElemType cur_e,ElemType &pre_e)
{
LinkList p=L->next;
while((p->next)&&(p->next->data!=cur_e))
p=p->next;
if(!(p->next)) return ERROR;
pre_e=p->data;
return OK;
}
//求后继
Status NextElem(LinkList L,ElemType cur_e,ElemType &next_e)
{
LinkList p=L->next;
while((p->next)&&(p->data!=cur_e))
p=p->next;
if(!(p->next)) return ERROR;
next_e=p->next->data;
return OK;
}
4.2 顺序表与链表的比较
- 存储方式:顺序表将数据元素按序存储在连续的内存空间中,而链表通过指针将各个数据元素链接起来,这些元素可以分布在内存的任意位置。
- 内存分配:顺序表在初始化时通常需要一次性申请一块连续的内存空间,大小往往是固定的或需要预估;相比之下,链表则按需为每个数据元素动态分配内存,因此对内存的使用更加灵活。
- 数据插入和删除:在顺序表中进行插入和删除操作时,可能需要移动大量元素以维护数据的连续性,这会导致较高的时间复杂度;而在链表中,由于数据元素不需要连续存放,因此插入和删除操作通常只需要改变相关节点的指针,具有较低的时间复杂度。
- 随机访问:顺序表支持快速的随机访问,可以直接通过索引快速定位到任何元素;链表由于是非线性存放的,要访问特定元素通常需要从头开始逐个遍历,因此在随机访问方面效率较低。
- 空间利用率:顺序表的空间利用率通常较高,因为它没有额外的空间开销;而链表则需要为每个节点存储额外的指针信息,这增加了空间开销。
- 内存碎片:顺序表可能会因为频繁的插入和删除操作产生内存碎片问题,而链表由于动态分配内存,不太会产生内存碎片。
- 循环链表与双向链表
第一个表的尾指针指向第二个表的头指针。
- 双向链表:节点中既有后继又有前驱。
- 双向链表的插入和删除:
Status ListInsert_DuL(DuLinkList &L,int i,ElemType e)
{
//在头结点的第i个位置插入元素
if(!(p=GetElem_Dul(L,i)))
return ERROR;
s=new DuiNode;//生成新节点s
s->date=e;
//关键的四句话
s->prior=p->prior;
s->prior->next=s;
s->next=p;
p->prior=s;
return OK;
}
Status ListInsert_DuL(DuLinkList &L,int i)
{
//删除第i个元素
if(!(p=GetElem_Dul(L,i)))
return ERROR;//p为null时,第i个元素不存在
//关键的两句话
p->prior->next=p->next;
p->next->prior=p->prior;
delete p;//释放被删节点的空间
return OK;
}
- 线性表的应用
一位大佬的总结
- 线性表的合并
总结
- 例题:
- 已知长度为n的线性表采用顺序存储结构。写
算法,删除线性表中所有值为x的元素。请先
对算法思想作简要文字说明,再写出算法具体代
码
- 已知长度为n的线性表采用顺序存储结构。写
void del_x_1(SqList &L, ElemType x) {
int k = 0; // 用于记录要删除的元素个数
int i = 0; // 用于遍历顺序表的索引
while (i < L.length) {
if (L.data[i] == x) {
k++; // 如果当前元素等于给定元素值,则增加要删除的元素个数
} else {
L.data[i - k] = L.data[i]; // 将不等于给定元素值的元素向前移动k个位置
}
i++; // 继续遍历下一个元素
}
L.length = L.length - k; // 更新顺序表的长度
}
- 设计一个高效算法,将顺序表L的所有元素逆置。
void Reverse(SqList &L) {
ElemType temp; // 用于交换元素的临时变量
for (int i = 0; i < L.length / 2; i++) {
temp = L.data[i]; // 将当前位置的元素保存到临时变量中
L.data[i] = L.data[L.length - i - 1]; // 将对称位置的元素赋值给当前位置
L.data[L.length - i - 1] = temp; // 将临时变量中保存的元素赋值给对称位置
}
}
//封装的实现数组的逆置
#include <iostream>
using namespace std;
void reverseArray(int arr[], int n) {
for (int i = 0; i < n / 2; i++) {
swap(arr[i], arr[n - i - 1]);
}
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int n = sizeof(arr) / sizeof(arr[0]);
reverseArray(arr, n);
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
return 0;
}
- 线性表的每个结点只能是一个简单类型,而链表的每个结点可以是一个复杂类型。()
答案:错误 - 将长度为n的单链表A链接在长度为m的单链表B之后的算法时间复杂度为答案:O(m)
链接在B之后,需要对B遍历,长度为m,因此遍历了m次找到尾结点。 - 链表的删除算法很简单,因为当删除链中某个结点后,计算机会自动地将后续的各个单元向前移动。答案:错误
链表的删除不会发生结点的移动,顺序表的删除才会发生结点的移动。 - 从头指针为la的带表头结点的有序顺序表中删除所有值相同的多余元素,并释放被删除结点的空间。
void purge(ListLink &la){
ListNode *p,*q,*t;
ElemType temp;
p=la->link;
while(p!=NULL){
q=p;
temp=p->data;
p=p->link;
if(p!=NULL&&temp!=p->data){
while(p!=NULL&&temp==p->data){
t=p;
p=p->link;
free(t);
}
q->link=p;
}
}
}