一、线性表的一维数组静态、动态分配
1.1一维数组静态分配
静态分配
#define Maxsize 50 //定义线性表的长度
typedef struct{
ElemType date[Maxsize]; //顺序表的元素
int length; //顺序表当前的长度
}SqList; // 使用typedef重新定义的顺序表类型
小结
1.存储空间的起始位置: 数组data,他的存储位置就是存储空间的存储位置
2线性表的最大存储容量: 数组长度MaxSize.
3.线性表当前长度: length
1.2一维数组动态分配
#define InitSize 100 //表长的初始定义
typedef struct{
ElemType *data; //指示动态分配数组的指针;ElemType是由typedef定义的数据元素的类型
int length, //动态数组的当前长度
MaxSize; //动态数组的最大容量
}SqlList; //使用typedef重新定义顺序表的类型
//动态分配空间
SqlList L;
L.date = (ElemType *)malloc(InitSize*sizeof(ElemType));
小结
1.找起点: 等号左边是我们指示动态数组的指针(即L.data)
2.改反参: malloc默认返回参数是void指针,需要在malloc前面强制转换类型(即数组指针的数据类型),写法是(数据类型 *)
3.赋参: 向malloc函数赋予你想分配的内存字节数,即表长 *数组数据类型字节数(sizeof)。
总的来记的话,malloc即memory allocate(内存分配),** 分配了多少呢?** 1size of(sizeof) 数据类型乘上线性表的长度,** 这段内存指向哪呢?** 转化为数组数据类型(ElemType *),指向数组指针( *data)。
二、线性表的操作
2.1顺序表的元素插入
/*
将元素e插入顺序表L中位序i的位置
*/
bool ListInsert(SqList &L, int i, ElemType e){
//下标[1,L.length + 1] 合法
if(i < 1 || i > L.length +1)
return false; //判断i的范围是否有效
//当前存储空间已满,不能插入
if(L.length >= Maxsize)
retrun false;
// 将第i个元素以及之后的元素后移
if (int j = L.length;j>=i,j--)
L.date[j] = L.data[j-1];
//插入
L.data[i-1] = e;
L.length++; /表长
return true;
}
小结
顺序表插入的4个步骤
1.定位置: 一个顺序表(一维数组)中的数据由相应的数组下标,插入位置如果小于第一个数据的下标或者高于最后一个数组的下标,就无法把元素插入到顺序表中。
2看空间: 顺序表存储是事先分配一段连续的内存存储单元,使用完了这段存储单元,也就没法再继续存储数据,所以插入之前要判断是否还有存储空间。
3移位置: 就像排队买车票的例子,有一个元素插入,后面的所有元素就要各自后移为这个元素腾出的空间。
4插入加表长: 将元素顺利插入到顺序表,现有的顺序表元素变多,表长也就相应的增大,所以插入结束需要将原表长相应加1。
我们可以用一首打油诗来帮助记忆:插入位置要规范((i<1||i>L.length + 1)),空间已满不可行((L.length >= MaxSize))。入表之前要移位(L.data[j] = L.data[j-1]),结束之后长加一(L.length++)。
2.2顺序存储结构删除操作
/*
删除顺序表L中第i(1<= i <=length)个位置的元素
e:记录删除删除元素的数据,通过引用返回。
*/
bool listDelete(SqlList &L, int i, ElemType &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[i-1] = L.data[j];
}
L.length--;
return true;
}
我们也可以用一首打油诗来帮助记忆:删除元素要在列((i<1||i>L.length)),找准位置取出来(e = L.data[i-1])。删除空位往前移(L.data[j-1] = L.data[j]),结束之后长减一(L.length–)。
2.3顺序表的线性查找
/*
查找顺序表中值为e的元素,如果查找成功,返回元素位序,否则返回0
*/
int LocateElem(SqList L,ElemType e){
int i;
for(i = 0; i<L.length: ++i)
{
if (L.data[i] ==e)
return i+1;
}
return 0;
}
三、单链表的操作
3.1链式线性表中的插入元素
3.1.1头插法建立
- 单链表节点类型描述
typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域,指向后继
}LNode,*LinkList; //LinkList等价于Lnode*
- 头插法建立单链表
LinkList createListByhead(LinkList &L){
Lnode *s; //工作指针
int x; //存输入元素
L = (LinkList)malloc(sizeof(Lnode)); //创建头结点
L->next = NULL; //初始为空表
scanf('%d',&x); //读取输入值
while(x != 9999){ //熟读9999表示创建结束
s = (LinkList)malloc(sizeof(Lnode)); //创建新结点
s->data = x; //设置数据域
//插入s到表头
s->next = L->next; //s后继设置L
L->next = s; //L的后继设置s
scanf('%d',&x);
}
return L; //返回头结点
}
我们可以用一句话来帮助记忆:声明结点建空表(Lnode s;L->next = NULL),数值赋给数据域(s->data = x),插入头与前点间(s->next = L->next;L->next = s)。
3.1.2尾插法建立链表
Linklist createLisyByTail(LinkList &L){
int x; //存输入元素
L = (LinkList)malloc(sizeof(LNode)); //创建头结点
LNode *s, //s为工作指针
*r = L; //r为表尾元素
scanf('%d',&x); //读取输入值
while(x != 9999){
s = (LinkList)malloc(sizeof(LNode));
s->data = x;
//插入s到表尾
r->next = s;
r = s;
scanf('%d',&x);
}
r->next = NULL; //尾巴置空
return L; // 返回头结点
}
3.2 单链表的查找
3.2.1按值查找结点
/*
从头开始遍历,返回其中数据域值为给定e的结点的指针。不存在则返回NULL
*/
LNode *locateElemByValue(LinkList L,ElemType e){
LNode *p = L->next;
while(p != NULL && p->data !=e)
p= p->netx
return p;
}
小结
1.设置工作指针: 设置指针负责指向要访问结点的指针域,并根据指针域移动指向下一个结点。
2.循环比较数据: 将给定数据与每个结点的数据域进行比较,相同则退出循环,返回系欸但指针;否则继续访问下一个结点。
3.返回相应指针: 找到相应的结点,则返回指向该结点的指针;否则返回NULL
整体看下来代码并不是很难,而且一句话就可以很轻松的记住:设指针(p = L->next),遍链表(p = p->next),返结点(return p)。
3.2.2 按序号查找结点值
//求有头结点的单链表长度
int length(LinkList L){
int len = 0; //初始长度
LNode *p = L->next //去掉头结点
//每向后遍历一个,长度加1
while(p != NULL){
len++;
p = p->next;
}
return len;
}
3.3 单链表的删除和插入
3.3.1 将值单链表的第i个位置上的结点删除
我们所要做的实际上就是一步,p->next = p->next->next ,用q来取代p->next,即是:q = p->next ; p->next = p->next->next
/*
删除第i个结点,并将数据域通过e返回,删除成功返回true,否则false
*/
bool deleteNode(LinkList L, int i,ElemType &e){
if (i<1 || i>length(L))
return false;
LNode *p, //被删除结点的前驱结点
*q; //辅助指针
p = getElemByPos(L,i-1);//被删除结点的前驱结点
//删除p的后继结点
q = p->next;
p-next = q->next; //将需要删除的结点从链表上取下
e = q->data;
free(q); //释放需要删除的结点
}
小结
1.设置辅助指针: 设置结点p,q分别用来指示要删除结点和它的前驱结点。
2.找到前驱结点: 遍历链表找到要删除结点的前驱结点
3.进行删除操作: 把要删除结点的前驱的后继变为被删除的结点的后继。
可以用一句话来帮助记忆:设指针(Lnode p,q),找前驱(p = GetElem(L,i-1)),删结点(q = p->next ; p->next = p->next->next)。
3.3.2 将值为x的结点插入到单链表的第i个位置上
void insertNode(Linklist L,int i, ElemType x){
if(i<1 || i>length(L)+1)
return false;
LNode *s = (LinkList)malloc(sizeof(LNode)) //创建一个新的结点
s->data =x ; //数据域赋值
LNode *p = getElemByPos(L,i-1); //找到第i个结点的前驱结点
//在p之后插入s
s->next = p->next;
p->next = s;
}
小结
1.判位置: 判断插入的位置是否在范围(if(i<1||i>Length(L)+1)
2.创结点: 如果在范围内,创建数据域为x的结点,等待插入(malloc)
3.查结点: 利用链表的插入操作插入结点。
3.4双链表的插入删除和静态链表
3.4.1 在p之后插入s和删除p的后继结点
typedef struct DNode{
ElemType data; //数据域
struct DNode *prior, //前驱指针
*next; //后继指针
}DNode,*DLinkList
插入代码
//在p之后,插入s
s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
删除代码
//删除p的后继结点q
p->next = q->next;
q->next->prior = p;
free(q);
3.4.2静态链表
数组比描述的链表
#define Maxsize 50
typedef struct{
ElemType data; //数据域
int next; //指针域:下一个元素的数组下标
}SLinklist[Maxsize];
8vMOneo-1668685368094)]
插入代码
//在p之后,插入s
s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
删除代码
//删除p的后继结点q
p->next = q->next;
q->next->prior = p;
free(q);
3.4.2静态链表
数组比描述的链表
#define Maxsize 50
typedef struct{
ElemType data; //数据域
int next; //指针域:下一个元素的数组下标
}SLinklist[Maxsize];