数据结构_线性表的链式存储

链表

  • 链表是链式存储方式实现的线性表
  • 逻辑上相邻的数据元素物理上不一定相邻

单链表

  • 单链表的节点有一个数据域和一个指针域,数据域存放数据,指针域用来指向下一个节点

单链表基本操作的实现(C语言)

#include <stdio.h>
#include <stdlib.h>
 
//单链表数据类型 
typedef struct LNode{ //节点 
	int data; //数据域 
	struct LNode *next; //指针域 
}LNode, *LinkList;

/*
typedef的用法,typedef 结构体 别名 
typedef struct LNode LNode; //强调单链表的节点 
typedef struct LNode *LinkList; //强调单链表本身 
*/

//单链表的初始化
/*
void InitList(LinkList L) //不带头节点 
{
	L = NULL; //空表,无任何节点 
}
*/
void InitList(LinkList L) //带头节点
{
	L = (LNode *) malloc(sizeof(LNode)); //默认为带头节点的单链表,后续以带头节点的单链表为例
	L->next = NULL; //头节点的指针域指向NULL 
} 

//单链表的创建
LinkList BuildListHead(LinkList L) //头插法
{
	int len, x, i;
	LNode *s;
	
	L = (LinkList) malloc(sizeof(LNode)); //创建头节点
	L->next = NULL; //初始化为空
	printf("请输入单链表的长度:");
	scanf("%d", &len);
	printf("\n"); 
	for(i = 0; i < len; i++)
	{
		printf("请输入单链表中节点的值:");
		scanf("%d", &x);
		s = (LNode *) malloc(sizeof(LNode)); //创建新节点 
		s->data = x;
		s->next = L->next;
		L->next = s;
		printf("\n"); 	
	 } 
	
	return L;
 } 

LinkList BuildListTail(LinkList L) //尾插法
{
	int len, x, i;
	LNode *s, *r;
	
	L = (LinkList) malloc(sizeof(LNode)); //创建头节点
    r = L; //初始化,设置一个尾指针 
	printf("请输入单链表的长度:");
	scanf("%d", &len);
	printf("\n"); 
	for(i = 0; i < len; i++)
	{
		printf("请输入单链表中节点的值:");
		scanf("%d", &x);
		s = (LNode *) malloc(sizeof(LNode)); //创建新节点 
		s->data = x;
		r->next = s;
		r = s;
		printf("\n"); 	
	 } 
	r->next = NULL; //尾指针指向空 
	
	return L;
 } 
 
//单链表的遍历
void TraversalList(LinkList L)
{
	LNode *p = L->next;
	while(p != NULL)
	{
		printf("%d ", p->data);
		p = p->next;
	 } 
	printf("\n");
 } 

//单链表的插入操作 
LNode* ListInsert(LinkList L, int pos, int ele) //按位插入 
{
	LNode *p; //指针p指向当前扫描到的节点 
	int j = 0; //当前p指向第几个节点,默认头节点为第0个节点
	p = L; //此时p指向单链表的头节点
	
	//寻找第pos-1个节点
	while(p!=NULL && j<pos-1)
	{
		p = p->next; //指向下一个节点 
		j++;
	} 
	//插入操作
	LNode *s = (LNode *) malloc(sizeof(LNode));
	s->data = ele;
	s->next = p->next;
	p->next = s;
	
	return s;
}

void ListInsertNext(LNode *p, int ele) //某个节点后插入 
{
	if(p == NULL)
	{
		return;
	}
	LNode *ss = (LNode *) malloc(sizeof(LNode));
	ss->data = ele;
	ss->next = p->next;
	p->next = ss;
}

void ListInsertPrior(LNode *p, int ele) //某个节点前插入 
{
	if(p == NULL)
	{
		return;
	}
	LNode *sss = (LNode *) malloc(sizeof(LNode));
	sss->next = p->next;
	p->next = sss; //指针不变,将值交换 
	sss->data = p->data;
	p->data = ele;
}

//单链表的删除操作
void ListDeletePos(LinkList L, int pos, int *ele) //按位删除 
 {
 	LNode *p; 
	int j = 0; 
	p = L;
	
	while(p!=NULL && j<pos-1)
	{
		p = p->next; //指向下一个节点 
		j++;
	} 
	LNode *q = p->next; //指针q指向被删除的节点
	*ele = q->data; //返回被删除节点的数据 
	p->next = q->next; //将p的指针域指向q的指针域 
	free(q); //释放q指针 
 }
 
void ListDeleteVal(LNode *p, int *ele) //按值删除 
 {
	LNode *q = p->next; //指针q指向被删除节点的后一个节点
	*ele = p->data;
	p->data = p->next->data; //将后一个节点的数据返回到被删除节点的数据 
	p->next = q->next; //将p的指针域指向q的指针域 
	free(q); //释放q指针  
 }
 
//链表的查找操作
int ListFindPos(LinkList L, int pos) //按位查找 
{
	int j = 0;
	LNode *p;
	p = L;
	
	if(pos < 0)
	{
		return;
	}
	while(p!=NULL && j<pos) 
	{
		p = p->next;
		j++;
	}
	
    return p->data; 
 } 

int ListFindVal(LinkList L, int ele) //按值查找 
{
	LNode *p = L->next;
	while(p!=NULL && p->data!=ele)
	{
		p = p->next;
	}
	
	return p->data;
 } 
 
int main()
{
	LinkList L; //声明一个指向单链表的指针 
	//L = BuildListHead(L); //使用头插法建立一个单链表 
	L = BuildListTail(L); //使用尾插法建立一个单链表 
	TraversalList(L); //遍历整个单链表
	 
	printf("-----------------------------\n");
	
	LNode *m;
	m = ListInsert(L, 3, 99); //在单链表中按位序插入节点,位置3插入节点,数据为99
	TraversalList(L); //遍历整个单链表
	ListInsertNext(m, 88); //在单链表中s节点后插入另一个节点ss,数据为88
	TraversalList(L); //遍历整个单链表
	ListInsertPrior(m, 77); //在单链表中s节点前插入另一个节点sss,数据为77 
	TraversalList(L); //遍历整个单链表
	
	printf("-----------------------------\n");
	
	int num1, num2;
	LNode *n;
	ListDeletePos(L, 3, &num1); //删除单链表中的节点,删除位置3上的节点并输出被删除的数据 
	printf("被删除的元素是:%d\n", num1);
	TraversalList(L); //遍历整个单链表
	n = ListInsert(L, 3, 100); //在单链表中按位序插入节点,位置3插入节点,数据为100
	TraversalList(L); //遍历整个单链表
	ListDeleteVal(n, &num2); //删除单链表中的节点,删除指定节点并输出被删除的数据 
	printf("被删除的元素是:%d\n", num2);
	TraversalList(L); //遍历整个单链表
	
	printf("-----------------------------\n");
	
	int data1;
	data1 = ListFindPos(L, 3); //按位查找链表的节点,查找位置3上的节点并输出节点数据 
	printf("查找节点的数据是:%d\n", data1); 
	
	printf("-----------------------------\n");
	
	int data2;
	data2 = ListFindVal(L, 88); //按值查找顺序表的元素,查找值为88的元素并输出
	printf("查找节点的数据是:%d\n", data2); 
	
	printf("-----------------------------\n");
	
	return 0;
} 

:单链表的建立有头插法和尾插法,头插法可以实现单链表的逆序。

单链表基本操作的分析

:按顺序表基本操作分析的方法进行分析,步骤相同,下面只给出平均情况下的时间复杂度。

插入操作的时间复杂度

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

删除操作的时间复杂度

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

查找操作的时间复杂度

按值查找:

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

按位查找:

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

单链表的特点

  • 顺序存取,不可随机存取
  • 需要一定空间存放指针
  • 不要求连续的存储空间
  • 扩展容量方便

双链表

循环链表

静态链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值