数据结构(C语言)—— 线性表小结

线性表

1、线性表的定义
线性表简称为表,是由n(n>=0)个数据元素(也叫节点或表元素)组成的有限序列。n=0时,该线性表成为空表。
表中各数据元素: 1)存在线性关系 2)结构类型完全一致

2、线性表的特点

  1. 唯一首元素
  2. 唯一尾元素
  3. 除首元素外,任何一个元素都有一个前驱
  4. 除尾元素外,任何一个元素都有一个后继
  5. 每个元素有一个位序(下标)

线性表的顺序存储

1.线性表的顺序存储原理
用一组地址连续的存储单位按线性表元素之间的逻辑顺序,一次存储线性表的数据元素。(属于静态存储,不能自由扩充)

数据元素的逻辑顺序和物理上的存储顺序完全一致,因此不需要另外建立空间来记录各个元素间
的关系

2、优、缺点
优点:随机存储。可以随机存取表中的任意一个数据元素(查快)
缺点:存储密度大。在插入、删除某元素时,需要移动大量元素(改慢);浪费储存空间

代码实现

#include<stdio.h>
#include<stdlib.h>

#define INIT_SIZE 10  //初始值
#define INCERMENT 5   //增加值
typedef int ElemType;   //自定义类型 (别名)
typedef struct {
	ElemType* elem;   //元素首地址
	int length;   //长度(元素个数)
	int listsize;  //容量(内存大小),用以判断顺序表是否为空
}SqList;   //顺序表名
//初始化
int Init_Sqlist(SqList* L) {
	L->elem = (ElemType*)malloc(INIT_SIZE * sizeof(ElemType));   //分配长度为INIT_SIZE字节的内存块
	if (!L->elem)  //if(L->elem == NULL)
		return -1;
	L->length = 0;
	L->listsize = INIT_SIZE;
	return 0;
}
//插入 , 在第i(下标)个位置插入元素e
int Insert_SqList(SqList* L, int i, ElemType e) {
	ElemType* newBase;  //保存新分配的内存首地址
	int j;
	if (i<0 || i>L->length)  //判断i的值是否有效
		return -1;
	if (L->length >= L->listsize) {   //判断内存是否满
		newBase = (ElemType*)realloc(L->elem , (L->listsize + INCERMENT) * sizeof(ElemType));   //将malloc()函数分配的地址扩大
		if (newBase == NULL)
			return -1;
		L->elem = newBase;
		L->listsize += INCERMENT;
	}
	for (j = L->length - 1; j >= i; j--){    //i下标后的值后移
		L->elem[j + 1] = L->elem[j];
	}
	L->elem[i] = e;
	L->length++;
	return 0;
}
//查找 , 找到值为e的位置
int Find_SqList(SqList L, ElemType e) {
	for (int i = 0; i < L.length ; i++) {
		if (L.elem[i] == e)
			return i + 1;
	}
	return 0;
}
//删除 , 第i(下标)位置的值
int Delect_SqList(SqList* L, int i) {
	if (i<0 || i>L->length)
		return -1;
	for (int j = i; j < L->length; j++)   //将i位置后的值前移,覆盖i位置的值
		L->elem[j] = L->elem[j + 1];
	L->length--;
	return 0;
}
//输出
void show(SqList L) {
	for (int i = 0; i < L.length; i++) {
		printf("%d\t", L.elem[i]);
	}
	printf("\n");
}
void main() {
	SqList L;
	Init_Sqlist(&L);
	Insert_SqList(&L, 0, 1);
	Insert_SqList(&L, 1, 2);
	Insert_SqList(&L, 2, 3);
	show(L);
	int a = Find_SqList(L, 3);
	printf("%d", a);
	printf("\n");
	Delect_SqList(&L, 1);
	show(L);
	system("pause");
}

在这里插入图片描述

线性表的链式存储

1.线性表的链式存储原理
用一组任意的存储单位来存放线性表的数据元素(存储单位可以是连续的,也可以是不连续的),数据元素之间的逻辑关系通过指针来指示。其中包括单链表、循环链表、双向链表。
2、优、缺点
优点:插入、删除通过修改链表指针,不需要移动数据元素(改快)
缺点:不可随机存取元素(查慢)

1、单链表

1)单链表存储原理
对于每一个数据元素来说,链表除了存放数据元素本身的值以外,还应一起存放数据元素的直接后继点所在存储单元的内存起始地址。
在这里插入图片描述

每个节点只有一个指向后继节点的指针。
每个节点包括数据域和指针域才可将数据元素之间的逻辑关系完全体现出来,(节点间的逻辑
结构比每个节点的实际内存地址显得更重要)

2) 头节点
定义:在链表头部加入一个特殊的节点,类型与数据节点相同,但其数据域不存放有效值,标识链表的头指针变量指向该节点。
作用:链表为空时头节点的头指针就指向头节点(头节点指针域为NULL);在插入和删除操作中无需进行特殊处理。
在这里插入图片描述

代码实现
#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;
typedef struct LNode {      //结点
	ElemType data;         //数据域
	struct LNode *next;    //指针域
}LNode, *LinkList;         //LNode* 等价于LinkList
//根据元素的值生成一个结点
LNode *CreateNode(ElemType e) {
	LNode *p = (LNode*)malloc(sizeof(LNode));
	p->data = e;
	p->next = NULL;
	return p;
}
//初始化
LinkList Init_LinkList() {
	return CreateNode(0);
}
//插入 , 在某结点curNode后插入新结点newNode
//当curNode为NULL时,表示在尾部插入
void Insert_LinkList(LinkList L, LNode* curNode, LNode* newNode) {
	LNode* p = curNode;
	if (!newNode) {
		return;
	}
	if (!curNode) {          //在尾部插入
		p = L;               //p为头结点
		while (p->next != NULL) {
			p = p->next;      //下一个
		}
	}
	newNode->next = p->next;    //插入新结点
	p->next = newNode;
	L->data++;
}
//查找 , 元素所在的结点位序(下标)
LNode* Find_LinkList(LinkList L, ElemType e) {
	LNode* p = L->next;   //首元
	int i = 0;
	while (p != NULL) {
		if (p->data == e)
			return i;
		p = p->next;
		i++;
	}
	return NULL;
}
//删除 , 按元素删除
void Delete_LinkList(LinkList L, ElemType e) {
	LNode* p, * c;   //p为前一个结点,c为当前结点
	p = L;
	while (p->next != NULL) {
		if (p->next->data == e) {
			c = p->next;
			p->next = p->next->next;
			L->data--;
			free(c);
			break;
		}
		p = p->next;
	}
}
//遍历
void show(LinkList L) {
	LNode* p;  //链表首元
	for (p = L->next; p != NULL; p = p->next) {
		printf("%d\t", p->data);
	}
	printf("\n");
}
void main() {
	LinkList L = NULL;
	LNode* node1, * node2, * node3, * node4, * node5;
	L = Init_LinkList();
	if (L == NULL)
		printf("链表初始化失败");
	//生成结点
	node1 = CreateNode(1);
	node2 = CreateNode(2);
	node3 = CreateNode(3);
	node4 = CreateNode(4);
	node5 = CreateNode(5);
	//尾部插入
	Insert_LinkList(L, NULL, node1);
	Insert_LinkList(L, NULL, node2);
	Insert_LinkList(L, node1, node3);
	//最前面插入
	Insert_LinkList(L, L, node4);
	Insert_LinkList(L, node2, node5);
	show(L);
	int i = Find_LinkList(L, 3);
	printf("%d", i);
	printf("\n");
	Delete_LinkList(L, 5);
	show(L);
}

在这里插入图片描述

2、循环链表

将单链表的尾结点的指针域指向头节点。
特性:从任何一个节点开始,都可以遍历整个链表。(单链表:整个链表遍历需从头节点开始)

代码实现
//初始化
LinkList Init_LinkList() {
	LinkList head = CreateNode(0);
	head->next = head;
	return head;
}
//插入 , 在某结点xNode后插入新结点newNode
//当xNode为NULL时,表示在尾部插入
void Insert_LinkList(LinkList head, LNode* xNode, LNode* newNode) {
	LNode* tail;
	LNode* p = head;
	while(p->next != head) {
		p = p->next;
	}
	tail = p;
	if (xNode == NULL || xNode == tail) {          //在尾部插入
		tail->next = newNode;          
		newNode->next = head;
	}else {
		newNode->next = xNode->next;
		xNode->next = newNode;
	}
	head->data++; 
}

3、双向链表

在链表节点中增加一个指向前驱节点的指针。
特性:可以快速找到节点前驱和后继
双向链表的储存结构描述

typedef struct DuLNode{
	ElemType data;
	struct DuLNode *prior;  //指向前驱
	struct DuLNode *next;   //指向后继
}DuLNode,* DuLinkList;
双向循环链表

双向链表中每个节点都有指向前驱和后继的指针,所以在插入、删除时对指针的操作必须在两个方向同时进行,否则可能会使其中一条链被截断(若截断可以利用另一条链来修补)。
因此,为了算法统一将双向链表的前向单链表和后向单链表共用一个头结点首尾相连,构成一个双向循环链表。

双向循环链表的某节点后插入
在这里插入图片描述

void inselem(DuLinkList L,ElemType e,DuLNode *p){
	DuLNode *s,*r;
	s = (DULNode*)malloc(sizeof(DuLNode));
	s->data = e;       //建立一个新节点s
	r = p->next;       
	s->next = r;       //s的后继为r
	r->prior = s;      //插入节点p后
	p->next = s;       
	s->prior = p;
}
在某节点前插入类似

双向循环链表的删除某节点
在这里插入图片描述

删除某节点,即是修改某节点前节点的next指针、后节点的prior指针,可以创建一个指针返回
删除的节点,最后释放删除节点空间(free())
  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
线性表是一种经常使用的基本数据结构,它可以用来存储一组具有相同数据类型的数据元素。在C语言中,线性表通常使用数组来实现。在实现线性表时,我们可以定义一个数组来存储元素,同时使用一个变量来记录线性表中元素的个数,以便于后续的插入、删除和查找等操作。 具体来说,线性表的实现可以包含以下几个主要的功能: 1. 初始化线性表:定义一个数组和一个变量,分别存储元素和元素个数,并将元素个数初始化为0,以便于后续操作。 2. 插入操作:向线性表中插入一个新的元素,具体实现可以包括以下步骤: - 判断线性表是否已满,若已满则不能再插入新元素,否则继续执行。 - 在线性表的末尾插入新元素,同时将元素个数加1。 3. 删除操作:从线性表中删除一个元素,具体实现可以包括以下步骤: - 判断线性表是否为空,若已空则不能再删除元素,否则继续执行。 - 根据用户指定的位置删除元素,并将后续元素向前移动一个位置,同时将元素个数减1。 4. 查找操作:在线性表中查找指定元素的位置,具体实现可以包括以下步骤: - 从线性表的第一个元素开始遍历,直到找到与指定元素相同的元素。 - 如果找到了相同的元素,则返回它的位置,否则返回查找失败的结果。 以上就是线性表的基本实现功能,通过这些操作可以方便地对线性表进行插入、删除和查找等操作,满足常见的应用需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值