【数据结构学习笔记】2.3线性表的链式表示
1.用代码定义一个单链表
struct LNode{
ElemType data;
struct LNode *next;
};
typedef struct LNode LNode;
typedef struct LNode *LinkList;
等价于
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
-
要表示一个单链表时,只需声明一个头指针L,指向单链表的第一个结点
LNode *L;
或者
LinkList L;
-
通过malloc增加一个新的节点:在内存中申请一个结点所需空间,并用指针p指向这个结点
struct LNode *p=(struct LNode *) malloc(sizeof(struct LNode));
-
typedef关键字---数据类型重命名
格式:typedef <数据类型> <别名>
typedef int zhengshu;
typedef int *zhengshuzhizhen;
int x=1; <=> zhengshu x=1;
int *p; <=> zhengshuzhizhen p;
typedef struct LNode LNode;
LNode *p=(LNode *) malloc(sizeof(LNode));
-
LNode * :强调返回的一个结点
LinkList:强调这是一个单链表
LNode * GetElem(LinkList L,int i){
int j=1
LNode *p=L->next
if(i==0)
return L
if(i<1)
return NULL
while(p!=NULL&&j<i){
p=p->next
j++
}
return p
}
2.不带头结点的单链表(写代码麻烦)
typedef struct LNode{
ElemType data;
struct LNODE *next;
}LNode,*LinkList;
bool InitList(LinkList &L){
L=NULL;
return true;
}
bool Empty(LinkList L){
if(L==NULL)
return true;
else
return false;
}
或:
bool Empty(LinkList L){
return (L==NULL);
}
void test(){
LinkList L;
InitList(L);
}
-
对第一个数据结点和后续数据结点的处理需要用不同的代码逻辑
-
对空表和非空表的处理需要用不同的代码逻辑
3.带头结点的单链表(写代码方便)
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
bool InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
if(L==NULL)
return false;
L->next=NULL;
return true;
}
bool Empty(LinkList L){
if(L->next==NULL)
return true;
else
return false;
}
void test(){
LinkList L;
InitList(L);
}

4.按位序插入(带头结点)
ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。(找到第i-1个结点,将新结点插入其后)

typedef struct LNode{
ElemType data
struct LNode *next
}LNode,*LinkList
//在第i个位置插入元素e(带头结点 )
bool ListInsert(LinkList &L,int i,ElemType e){
if(i<1)
return false
LNode *p
int j=0
p=L
while(p!=NULL&&j<i-1){ //循环找到第i-1个结点
p=p->next
j++
}
if(p==NULL) //i值不合法
return false
LNode *s=(LNode *)malloc(sizeod(LNode))
s->data=e
s->next=p->next
p->next=s
return true
}
5.按位序插入(不带头结点)
//在第i个位置插入元素e(不带头结点 )
bool ListInsert(LinkList &L,int i,ElemType e){
if(i<1)
return false
if(i==1){ //插入第1个结点的操作与其他结点操作不同
LNode *s=(LNode *)malloc(sizeod(LNode))
s->data=e
s->next=L;
L=s
return true
}
LNode *p
int j=1
p=L
while(p!=NULL&&j<i-1){ //循环找到第i-1个结点
p=p->next
j++
}
if(p==NULL) //i值不合法
return false
LNode *s=(LNode *)malloc(sizeod(LNode))
s->data=e
s->next=p->next
p->next=s
return true
}
查找的部分可由:LNode *p=GetElem(L,i-1); 来封装
6.指定结点的后插操作
typedef struct LNode{
ElemType data
struct LNode *next
}LNode,*LinkList
//在第i个位置插入元素e(带头结点 )
bool ListInsert(LinkList &L,int i,ElemType e){
if(i<1)
return false
LNode *p
int j=0
p=L
while(p!=NULL&&j<i-1){ //循环找到第i-1个结点
p=p->next
j++
}
return InsertNextNode(p,e)
}
//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p,ElemType e){
if(i<1)
return false
LNode *s=(LNode *)malloc(sizeod(LNode))
if(s==NULL) //分配内存失败
return false
s->data=e
s->next=p->next
p->next=s
return true
}

后插时间复杂度为:O(1)
7.指定结点的后插操作
思路1:

时间复杂度为:O(n)
思路2:

时间复杂度为:O(1)
//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p,ElemType e){
if(p==NULL)
return false
LNode *s=(LNode *)malloc(sizeod(LNode))
if(s==NULL) //分配内存失败
return false
s->next=p->next
p->next=s
s->data=p->data
p->data=e
return true
}
思路3:

8.按位序删除(带头结点)
ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。
typedef struct LNode{
ElemType data
struct LNode *next
}LNode,*LinkList
bool ListDelete(LinkList &L,int i,ElemType &e){
if(i<1)
return false
LNode *p
int j=0
p=L
while(p!=NULL&&j<i-1){ //循环找到第i-1个结点
p=p->next
j++
}
if(p==NULL) //i值不合法
return false
if(p->next==NULL) //第i-1个结点之后已无其他结点
return false
LNode *q=p->next
e=q->data
p->next=q->next
free(q)
return true
}
//删除指定结点 p,存在bug,问题在于只有一个数据的链表
bool DeleteNode(LNode *p){
if(p==NULL)
return false
LNode *q=p->next
p->data=p->next->data
p->next=q->next
free(q)
}
查找的部分可由:LNode *p=GetElem(L,i-1); 来封装
9.按位查找
/*思路1:*/
//按位查找,返回第i个元素(带头结点)
LNode * GetElem(LinkList L,int i){
if(i<0)
return NULL
LNode *p
int j=0
p=L
while(p!=NULL&&j<i){ //循环找到第i-1个结点
p=p->next
j++
}
return p
}
/*思路2:*/
LNode * GetElem(LinkList L,int i){
int j=1
LNode *p=L->next
if(i==0)
return L
if(i<0)
return NULL
while(p!=NULL&&j<i){
p=p->next
j++
}
return p
}
10.按值查找
LNode *LocateElem(LinkList L,ElemType e){
LNode *p=L->next;
while(p!=NULL&&p->data!=e)
p=p->next;
return p;
}
11.求表的长度
//求表的长度
int Length(LinkList L){
int len=0
LNode *p=L
while(p->next!=NULL){
p=p->next
len++
}
return len
}
12.尾插法建立单链表
LinkList List_TailInsert(LinkList &L){ //正向建立单链表
int x
L=(LinkList)malloc(sizeof(LNode))
LNode *s,*r=L
scanf("%d",&x)
while(x!=9999){ //输入9999表示结束
//在r结点之后插入元素x
s=(LNode *)malloc(sizeof(LNode))
s->data=x
r->next=s
r=s
scanf("%d",&x)
}
r->next=NULL
return L
}

13.头插法建立单链表(链表逆置)
LinkList List_HeadInsert(LinkList &L){ //逆向建立单链表
LNode *s
int x
L=(LinkList)malloc(sizeof(LNode))
L->next=NULL
while(x!=9999){ //输入9999表示结束
s=(LNode *)malloc(sizeof(LNode))
s->data=x
s->next=L->next
L->next=s
scanf("%d",&x)
}
return L
}
-
此代码L->next=NULL;是否能删除?
不能。因为如果此句删除头结点的指针将会指向内存中未知数据域(存在脏数据),等所有插入操作完成后将会将最后的指针指向此数据域,导致链表内数据错误。
故只要是初始化单链表,都先把头指针指向NULL。

14.双链表的初始化(带头结点)

typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
bool InitDLinkList(DLinkList &L){
L=(DNode *)malloc(sizeof(DNode));
if(L==NULL)
return false;
L->prior=NULL;
L->next=NULL;
return true;
}
bool Empty(DLinkList L){
if(L->next==NULL)
return true;
else
return false;
}
void testDLinkList(){
DLinkList L;
InitDLinkList(L);
}
15.双链表的插入
//双链表的插入
bool InsertNextDNode(DNode *p,DNode *s){
if(p==NULL||s==NULL) //非法参数
return false
s->next=p->next
if(p->next!=NULL) //如果p结点有后继结点
p->next->prior=s
s->prior=p
p->next=s
return true
}

16.双链表的删除与摧毁
bool DeleteNextDNode(DNode *p){
if(p==NULL) return false;
DNode *q=p->next;
if(q==NULL) return false;
p->next=q->next;
if(q->next!=NULL)
q->next->prior=p;
free(q);
return true;
}
void DestoryList(DLinkList &L){
while(L->next!=NULL)
DeleteNextDNode(L);
free(L);
L=NULL;
}

17.双链表的遍历
while(p!=NULL){
p=p->next;
}
while(p!=NULL){
p=p->prior;
}
while(p->prior!=NULL){
p=p->prior;
}
18.循环单链表

bool InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
if(L==NULL)
return false;
L->next=L;
return true;
}
bool Empty(LinkList L){
if(L->next==L)
return true;
else
return false;
}
bool isTail(LinkList L,LNode *p){
if(p->next==L)
return true;
else
return false;
}
19.循环双链表

typedef struct DNode{
ElemType data
struct DNode *prior,*next
}DNode,*DLinkList
//初始化一个循环双链表
bool InitDLinkList(DLinkList &L){
L=(DNode *)malloc(sizeof(DNode))
if(L==NULL) //内存不足,分配失败
return false
L->prior=L
L->next=L
return true
}
//判断循环双链表是否为空
bool Empty(DLinkList L){
if(L->next==L)
return true
else
return false
}
//判断结点p是否为循环双链表的表尾结点
bool isTail(DLinkList L,DNode *p){
if(p->next==L)
return true
else
return false
}
void testDLinkList(){
//初始化循环双链表
DLinkListL L
InitDLinkList(L)
}
//插入结点s
s->next=p->next
p->next->prior=s
s->prior=p
p->next=s
//删除结点s
p->next=q->next
q->next->prior=p
free(q)
20.用代码定义一个静态链表
#define MaxSize 10
struct Node{
ElemType data;
int next;
};
void testSLinkList(){
struct Node a[MaxSize];
}
#define MaxSize 10
struct Node{
ElemType data;
int next;
}SLinkList[MaxSize];
void testSLinkList(){
SLinkList a;
}
#define MaxSize 10
struct Node{
ElemType data;
int next;
};
typedef struct Node SLinkList[MaxSize];
void testSLinkList(){
struct Node a[MaxSize];
}
