IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构(C语言)—— 线性表小结 -> 正文阅读

[数据结构与算法]数据结构(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())
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-26 22:27:24  更:2021-12-26 22:28:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 17:32:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码