线性表——单链表(C语言版)

链表介绍

        1、用一组物理位置任意的存储单元来存放线性表的数据元素。
        2、这组存储单元即可以是连续的,也可以是不连续的,甚至是零散分布在内存的任意位置的。
        3、链表中元素的逻辑次序和物理次序不一定相同。

单链表是由头指针唯一确定,因此单链表可以用头指针的名字命名。

各节点有两个域组成
        数据域:存储元素数值,数据
        指针域:存储直接后继结点的存储位置

相关术语

1、结点:数据元素的存储映像,由数据域和指针域两部分组成
2、链表:n个节点由指针链组成一个链表
3、头指针:只想链表中第一个节点的指针
4、首元节点:链表中存储第一个数据元素a1的节点
5、头节点:在链表的首元节点之前附设的一个结点

 链表种类

        1、单链表:结点只有一个指针域的链表,称为单链表或线性链表。

        2、双链表:结点有两个指针域的链表,称为双链表。


        3、循环链表:首尾相接的链表称为循环链表 

 

讨论

1、如何表示空表

        无头结点时,头指针为空时表示空表。
        有头结点时,当头结点的指针域为空时,表示空表

2、在链表中设置头结点有什么好处

        1、便于首元结点的处理
        首元结点的地址保存在投机点的指针域中,所以在链表的第一个位置上的操作和其他位置一致,无须进行特殊处理。

        2、便于空表和非空表的统一处理
         无论链表是否为空,头指针都是指向头节点的非空指针,因此空表和非空表的处理也就统一了。

         3、头结点的数据域内装的是什么
        头结点的数据域可以为空,也可以放线性表长度等附加信息,但此节点不能计入链表长度值。

 实现代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define TURE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define MAXSIZE 10
#define NULL 0


//status是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef char ElemType;
//定义单链表(带头结点)
typedef struct Lnode{
	ElemType data;
	struct Lnode *next;
}Lnode, *LinkList;

//单链表初始化
Status InitList(LinkList *L){
	(*L) = (LinkList)malloc(sizeof(Lnode));
	(*L)->next = NULL;
	return OK;
}

//判断链表是否为空
int ListEmpty(LinkList L){
	if (L->next)
		return 0;
	else
		return 1;
}

//单链表销毁
Status DestrouList(LinkList *L){
	LinkList p;
	while (*L)
	{
		p = (*L);
		(*L) = (*L)->next;
		free(p);
	}
	return OK;
}

//清空链表
Status ClearList(LinkList *L){
	Lnode *p, *q;
	p = (*L)->next;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
	return OK;
}

//求链表表长
int ListLength(LinkList L){
	LinkList p;
	p = L->next;
	int i = 0;
	while (p)
	{
		i++;
		p = p->next;
	}
	return i;
}

//取值----取单链表中第i个元素的内容
Status GetElem(LinkList L, int i, ElemType *e){
	LinkList p=L->next;
	int j = 1;
	while (p&&j < i){
		p = p->next;
		j++;
	}
	if (!p || j > i)
		return ERROR;
	*e = p->data;
	return OK;
}

//按值查找----根据指定数据获取数据所在位置(地址)
Lnode *LocateElem(LinkList L, ElemType e){
	LinkList p;
	p = L->next;
	while (p&&p->data!=e)
	{
		p = p->next;
	}
	return p;
}

//按值查找----根据指定数据获取该数据位置序号
int LocateELem(LinkList L, ElemType e){
	LinkList p = L->next;
	int j = 1;
	while (p&&p->data!=e)
	{
		p = p->next;
		j++;
	}
	if (p)
		return j;
	else
		return 0;
}

//插入----在第i个节点前插入值为e的新节点
Status ListInsert(LinkList *L,int i,ElemType e){
	LinkList p = *L;
	int j=0;
	while (p&&j<i-1)
	{
		p = p->next;
		j++;
	}
	if (!p||j>i-1)
		return ERROR;
	LinkList s = (LinkList)malloc(sizeof(Lnode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return OK;
}

//删除----删除第i个节点
Status ListDelete(LinkList *L, int i, ElemType *e){
	LinkList p = *L;
	int j = 0;
	LinkList q;
	while (p->next&&j < i - 1){
		p = p->next;
		j++;
	}
	if (!(p->next) || j > i - 1)
		return ERROR;
	q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);
	return OK;
}

//建立单链表(头插法)
void CreateList_L(LinkList *L,int n){
	(*L) = (LinkList)malloc(sizeof(Lnode));
	(*L)->next = NULL;
	for (int i = n; i >0; i--)
	{
		LinkList p = (LinkList)malloc(sizeof(Lnode));
		scanf("%c",&(p->data));
		getchar();
		p->next = (*L)->next;
		(*L)->next = p;
	}
}

//建立单链表(尾插法)
void CreateList_R(LinkList *L, int n){
	(*L) = (LinkList)malloc(sizeof(Lnode));
	LinkList p;
	(*L)->next = NULL;
	LinkList r = (*L);
	
	for (int i = 0; i < n; i++){
		p = (LinkList)malloc(sizeof(Lnode));
		scanf("%c", &(p->data));
		getchar();
		p->next = NULL;
		r->next = p;
		r = p;
	}
}

int main(void){
	LinkList L;
	ElemType e;
	int n = 5;
	//测试头插法(倒叙)
	//CreateList_L(&L,n);
	//测试尾插法
	CreateList_R(&L, n);
	//测试删除
	ListDelete(&L,1,&e);
	//测试插入
	ListInsert(&L, 2, 'o');
	//测试查找位置序号
	printf("字母s的序号为%d\n", LocateELem(L, 's'));
	//测试查找位置地址
	printf("这是字母s的地址%d\n", LocateElem(L, 's'));
	//测试表长
	printf("该表长%d\n", ListLength(L));
	//测试清空链表
	ClearList(&L);
	//测试判断表是否为空
	printf("%d\n", ListEmpty(L));
	//测试销毁
	printf("%d\n", DestrouList(&L));

}

时间复杂度

        1.查找

        因为线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间复杂度为O(n)

         2.插入删除
        因线性表不需要移动元素,只要修改指针,一般情况下时间复杂度为O(1)
        但是,如果要在单链表中进行前插或删除操作,由于从头查找前驱结点,所耗时间复杂度为O(n)。
        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值