单链表的基本操作(带头结点与不带头结点)

0.定义结点

typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode, *LinkList;
//LNode表示节点,LinkList表示头指针

1.初始化

①带头结点

bool InitList(LinkList &L){
    L = (LNode *)malloc(sizeof(LNode));//头指针指向头结点
    //判断是否分配成功
    if(L == NULL)
        return false;
    //初始化指向空
    L ->next = NULL;
    return true;
}

②不带头结点

bool InitList(LinkList &L){
    L = NULL;//初始化为空表,头指针指向空
    return true;
}

2.判空

①带头结点

bool Empty(LinkList L) {
	if(L->next == NULL)
		return true;
	else
		return false;
}

②不带头结点

bool Empty(LinkList L) {
	if(L == NULL)
		return true;
	else
		return false;
}

3.创建

3.1头插法(常应用于链表逆置)

①带头结点

LinkList List_HeadInsert(LinkList &L) {
	InitList(L);//初始化:创建头结点;初始化为空链表
	LNode *s;
	int x;
	scanf("%d", &x);
	while(x != 9999) {//输入9999表示结束
		s = (LNode*)malloc(sizeof(LNode));
		s -> data = x;
		s -> next = L -> next;
		L -> next = s;
		scanf("%d", &x);
	}
	return L;
}

②不带头结点

LinkList List_HeadInsert(LinkList &L) {
	InitList(L);//初始化:初始化为空链表
	LNode *s;
	int x;
	scanf("%d", &x);
	while(x != 9999) {//输入9999表示结束
		s = (LNode*)malloc(sizeof(LNode));
		s -> data = x;
		s -> next = L;
		L = s;
		scanf("%d", &x);
	}
	return L;
}

每个结点插入的时间复杂度为:O(1)
总时间复杂度:O(n)

3.2尾插法

①带头结点

LinkList List_TailInsert(LinkList &L) {
	InitList(L);//初始化:创建头结点;初始化为空链表
	LNode *s, *r = L;//r为表尾指针
	int x;
	scanf("%d", &x);
	while(x != 9999) {//输入9999表示结束
		s = (LNode*)malloc(sizeof(LNode));
		s -> data = x;
		r -> next = s;
		r = s;
		scanf("%d", &x);
	}
	r -> next = NULL;
	return L;
}

②不带头结点

LinkList List_TailInsert(LinkList &L) {
	InitList(L);//初始化:初始化为空链表
	LNode *s, *r = L;//r为表尾指针
	int x;
	scanf("%d", &x);
	while(x != 9999) {//输入9999表示结束
		s = (LNode*)malloc(sizeof(LNode));//创建新结点
		s -> data = x;
		if (L == NULL) {
			L = s;
			r = L;
		}
		else {
			r -> next = s;
			r = s;
		}
		scanf("%d", &x);
	}
	r -> next = NULL;
	return L;
}

由于附设了一个尾指针,时间复杂度与头插法相同。

4.查找

4.1按序查找

①带头结点

LNode *GetElem(LinkList L, int i) {
	//判断i是否合法
	if(i < 0)
		return NULL;
	int j = 0;
	LNode *p = L;//p指向第0个结点
	while(p != NULL && j < i){
		p = p -> next;
		j++;
	}
	return p;//i>len或查找不成功时返回NULL
}

②不带头结点

LNode *GetElem(LinkList L, int i) {
	//判断i是否合法
	if(i < 1)
		return NULL;
	int j = 1;
	LNode *p = L;//p指向第1个结点
	while(p != NULL && j < i){
		p = p -> next;
		j++;
	}
	return p;//i>len或查找不成功时返回NULL
}

4.2按值查找

①带头结点

LNode *LocateElem(LinkList L, ElemType e){
    LNode *p = L -> next ;//L指向头结点(第0个结点),p指向第1个结点
    while ( p != NULL && p -> data != e )
        p = p -> next;
    return p ;//查找失败返回NULL
 }

②不带头结点

LNode *LocateElem(LinkList L, ElemType e){
    LNode *p = L;//p指向第1个结点
    while ( p != NULL && p -> data != e )
        p = p -> next;
    return p ;//查找失败返回NULL
 }

查找的时间复杂度都为O(n)

5.插入

5.1 后插(将新结点插入到第i个位置上,即在第i-1个位置后面插入)

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;
}

①带头结点

bool ListInsert(LinkList &L, int i, ElemType e){
    if(i < 1)
        return false;
    LNode *p = GetElem(L, i-1);
    return InsertNextNode(p, 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 = GetElem(L, i-1);
    return InsertNextNode(p, e);
}

后插的时间复杂度:O(n)

5.2对给定结点p的前插

方案1:转化为上一结点的后插

需要给定头指针,从头开始找到上一结点。

①带头结点
bool InsertPriorNode(LinkList L, LNode *p, ElemType e){
    LNode *q = L;
    while(q -> next != q)
        q = q -> next;
    return InsertNextNode(q, e);
}
②不带头结点
bool InsertPriorNode(LinkList L, LNode *p, ElemType e){
    LNode *q = L;
    if(p == q){
        LNode *s = (LNode *)malloc(sizeof(LNode));
        s -> data = e;
        s -> next = L;
        L = s;
        return true;
    }
    while(q -> next != q)
        q = q -> next;
    return InsertNextNode(q, e);
}

时间复杂度:O(n)

方案2:后插再交换位置

有无头结点相同

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 = e;
    return true;
}

时间复杂度:O(1)

6.删除

6.1删除第i个结点

bool DeleteNextNode(LNode *p, ElemType &e){
   //i值不合法
   if(p == NULL || p -> next == NULL)
       return false;
   LNode *q = p -> next;
   e = q -> data;
   p -> next = q -> next;
   free(q);
   return true;
   
}

①带头结点

bool ListDelete(LinkList &L, int i, ElemType &e){
    if(i < 1)
       return false;
    LNode *p = GetElem(L, i-1)
    return DeleteNextNode(p, e);
}

②不带头结点

bool ListDelete(LinkList &L, int i, ElemType &e){
    if(i < 1)
        return false;
    if(i == 1){
    	LNode *q = L;
    	e = q -> data;
    	L = q -> next;
        free(q);
        return true;
    }
    LNode *p = GetElem(L, i-1)
    return DeleteNextNode(p, e);
}

6.2删除给定结点p

方案1:找到前驱结点,执行删除操作

需要给定头指针,从头开始找到上一结点。

①带头结点
bool DeleteNode(LNode *p, ElemType &e){
    LNode *q = L;
    while(q -> next != q)
        q = q -> next;
    return DeleteNextNode(q, e);
}
②不带头结点
bool DeleteNode(LNode *p, ElemType &e){
    LNode *q = L;
    if(p == q){
        L = p -> next;
        free(p);
        return true;
    }
    while(q -> next != q)
        q = q -> next;
    return DeleteNextNode(q, e);
}

时间复杂度:O(n)

方案2:将p结点的后继结点赋予自身,删除后继结点

有无头结点相同

bool DeleteNode(LNode *p, ElemType &e){
    if(p == NULL )
    	return false;
    e = p -> data;
    LNode *q = p -> next;
    if(q == NULL )
    	free(p);
    	return true;
    p -> data = q -> data;
    p -> next = q -> next;
    free(q);
    return true;
}

时间复杂度:O(1)

7.求表长

①带头结点

int Length(LinkList L){
    int len = 0;
    if(L == NULL)
		return false;
    while(L->next){
        len++;
        L = L -> next;
    }
    return len;
}

②不带头结点

int Length(LinkList L){
    int len = 0;
    if(L == NULL)
		return false;
    while(L){
        len++;
        L = L -> next;
    }
    return len;
}

时间复杂度:O(n)

7.销毁

有无头结点相同

void DestroyList(LinkList &L){
	LNode *q;
	while(L){
		q = L;
   		L= L -> next
   		free(q);
	}
	L = NULL;
}

时间复杂度:O(n)

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值