数据结构与算法(四)

目录

一.单链表的建立

1.尾插法

2.头插法

二.双链表

1.双链表的初始化

2.双链表的插入

 3.双链表的删除

 4.双链表的遍历


一.单链表的建立

1.尾插法

第一种方法

尾插法建立单链表:
初始化单链表
设置变量length记录链表长度
While循环{
每次取一个数据元素e;
ListInsert (L, length+1, e)插到尾部;

length++;
}
但是每次都要从头开始遍历,时间复杂度为O(n2).

第二种方法:

LinkList List_Taillnsert(LinkList &L){ // 正向建立单链表

int x;//设ElemType为整型

L=(LinkList)malloc(sizeof(LNode)); //建立头结点

LNode *s,*r=L;//r为表尾指针

scanf("%d" ,&x);//输入结点的值

while(x!=9999){//输入9999表示结束

s=(LNode * )malloc(sizeof(LNode));

s->data=x;

r->next=s;

r=s;//r指向新的表尾结点

scanf("%d",&x);

}

r->next=NULL;//尾结点指针置空

return L;

}

后插法,更较简单,不用一次次遍历。

2.头插法

头插法建立单链表:
初始化单链表
While 循环 {
每次取一个数据元素e;

InsertNextNode (L, е);
}

//后插操作:在p結点之后插入元素e

bool InsertNextNode (LNode *p, ElemType e){

if (p==NULL)

    return false;

LNode *S = (LNode * )malloc(sizeof (LNode));
if (s==NULL)//内存分配失败

    return false;

s->data = e;//用结点s保存数据元素e

s->next=p->next;

p->next=s;//將结点s连到p之后

return true;

}

要养成好习惯,只要是初始化单链表,都先把头指针指向NULL(L->next=NULL;),初始为空链表

头插法就相当于链表的逆置

头插法和尾插法:核心就是初始化操作,指定结点的后插操作。

二.双链表

1.双链表的初始化

头结点的prior、next都指向NULL

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;//头结点的prior永远指向NULL

L->next = NULL;、/头结点之后暂吋还没有结点

return true;
}

void testDLinkList() {//初始化双链表

DLinklist L;

InitDLinkList(L);//后续代码
}

2.双链表的插入

注意新插入结点、前驱结点、后继结点的指针修改
边界情况:新插入结点在最后一个位置,需特殊处理

修改指针时要注意顺序

//在p结点之后插入s结点

bool Inser tNextDNode(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;
}

 3.双链表的删除

注意删除结点的前驱结点、后继结点的指针修改

边界情况:如果被删除结点是最后-个数据结点,需特殊处理

//删除p结点的后继结点

bool DeleteNextDNode(DNode *p){

if (p==NULL)

return false;

DNode *q = p->next;//找到p的后继结点q

if (q==NULL)

return false;//p没有后继

p->next=q->next;

if (q->next !=NULL)//q结点不是最后一个结点

    q->next->prior=p;

free(q);//释放结点空间

return true;

}

如果要将双链表删除,则要加上这个函数

void DestoryList(DLinklist &L){//循环释放各个数据结点

while (L->next != NULL)
    
    DeleteNextDNode(L);
free(L); //释放头结点

L=NULL;//头指针指向NULL

}

 4.双链表的遍历

从一个给定结点开始,后向遍历、前向遍历的实现(循环的终止条件)

链表不具备随机存取特性,查找操作只能通过顺序遍历实现

后向遍历

while (p!=NULL){
//对结点p做相应处理,如打印
p= p->next;
}

前向遍历

while (p!=NULL){
//对结点p做相应处理
p= p->prior;
}

前向遍历(跳过头结点)

while (p-> prior != NULL){
//对结点p做相应处理
p= p->prior;
}

双链表不可随机存取,按位查找、按值查找操作都只能用遍历的方式实现。时间复杂度O(n)
 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值