第二章 数据结构-单链表

第二章 数据结构-单链表

一、定义

1.概念

单链表:链式存储。每个节点除了存放数据元素外,还要存储指向下一个节点的指针。

优点:不要求大片连续空间,改变容量方便。

缺点:不可随机存取,要耗费一定空间存放指针。

2.代码实现

2.1 单链表定义
struct LNode{				//定义单链表节点类型
    ElemType data;			//每个节点存放一个数据元素 数据域
    struct LNode *next;		//指针指向下一个节点	指针域
}

struct LNode *p=(struct LNode *)malloc(sizeof(struct LNode));
//增加一个新的结点:在内存中申请一个结点所需空间,并用指针p指向这个结点
2.2 不带头结点的单链表
typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;

//初始化一个空的单链表
bool InitList(LinkList &L){
    L=NULL;
    return true;
}

//判断单链表是否为空
bool Empty(LinkList L){
    return (L==NULL);
}

void test(){
	LinkList L;	//声明一个指向单链表的指针
    InitList(L);
}
2.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);
}

ps:头结点不存储数据

LinkList等价于LNode *,前者强调这是链表,后者强调这是结点。

二、插入与删除

1.插入操作

1.1 按位序插入(带头结点)

ListInsert(&L,i,e)插入操作。在表L中第i个位置上插入指定元素e。

代码:

//在表L中第i个位置上插入指定元素e(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e){
    if(i<1)	return false;
    LNode *p;	//指针p指向当前扫描到的结点
    int j=0;	//当前p指向的是第几个结点
    p=L;		//L指向头结点,头结点是第0个结点(不存数据)
    while(p!=NULL && j<i-1){	//循环找到第i-1个结点
		p=p->next;
        j++;
    }
    if(p==null)	return false;	//i值不合法
    LNode *s=(LNode *)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return true;
}

平均时间复杂度: O ( n ) O(n) O(n)

1.2 按位序插入(不带头结点)

ListInsert(&L,i,e)插入操作。在表L中第i个位置上插入指定元素e。

代码:

//在表L中第i个位置上插入指定元素e(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e){
    if(i<1)	return false;
    if(i==1){	//插入第1个结点的操作与其他结点操作不同
        LNode *s=(LNode *)malloc(sizeof(LNode));
        s->data=e;
        s->next=L;
        L=s;	//头指针指向新结点
        return true;
    } 
    LNode *p;	//指针p指向当前扫描到的结点
    int j=1;	//当前p指向的是第几个结点
    p=L;		//L指向头结点,头结点是第0个结点(不存数据)
    while(p!=NULL && j<i-1){	//循环找到第i-1个结点
		p=p->next;
        j++;
    }
    if(p==null)	return false;	//i值不合法
    LNode *s=(LNode *)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return true;
}
1.3 指定结点的后插操作
//后插操作:在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->next=p->next;
    p->next=s;
    return true;
}

时间复杂度: O ( 1 ) O(1) O(1)

1.4 指定结点的前插操作
//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p,ElemType e){
	if(p==NULL)	return false;
    LNode *s=(LNode *)malloc(sizeof(LNode));
    if(s==NULL)	return false;	//内存分配失败
    s->next=p->next;
    p->next=s;
    s->data=p->data;
    p->data=s;
    return true;
}

时间复杂度: O ( 1 ) O(1) O(1)

2.删除操作

2.1 按位序删除(带头结点)

ListDelete(&L,i,&e)删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。

bool ListDelete(LinkList &L,int i,ElemType &e){
    if(i<1) return false;
    LNode *p;   //指针p指向当前扫描到的结点
    int j=0;    //当前p指向的是第几个结点
    p=L;
    while(p!=NULL && j<i-1){
        p=p->next;
        j++;
    }
    if(p==NULL) return false;   //i值不合法
    if(p->next==NULL) return false;   //i-1个结点之后已无其他结点
    LNode *q=p->next;   //令q指向被删除结点
    e=q->data;          //用e返回元素的值
    p->next=q->next;
    free(q);
    return true;
}

时间复杂度: O ( n ) O(n) O(n)

2.2 指定结点的删除
//删除指定结点p
bool DeleteNode(LNode *p){
    if(p==NULL) return false;
    LNode *q=p->next;       //令q指向*p的后继结点
    p->data=p->next->data;  //和后继结点交换数据域
    p->next=q->next;        
    free(q);
    return true;
}

时间复杂度: O ( 1 ) O(1) O(1)

三、查找

1.按位查找

//按位查找,返回第i个元素(带头结点)
LNode *GetElem(LinkList L,int i){
    if(i<1) return false;
    LNode *p;   //指针p指向当前扫描到的结点
    int j=0;    //当前p指向的是第几个结点
    p=L;
    while(p!=NULL && j<i-1){
        p=p->next;
        j++;
    }
    return p;
}

时间复杂度: O ( n ) O(n) O(n)

2.按值查找

//按值查找1,找到数据域等于e的结点
LNode *LocateElem(LinkList L,ElemType e){
    LNode *p=L->next;
    while (p!=NULL && p->data!=e){
        p=p->next;
        return p;
    }
}

时间复杂度: O ( n ) O(n) O(n)

本文为个人学习笔记,若有问题可一起讨论学习
更多内容可以关注个人博客:Ackow的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值