从头开始嵌入式编程学习-数据结构-线性表-链式线性表

学习流程主要包括分为11个部分
  1. 绪论
  2. 线性表
  3. 栈和队列
  4. 递归和分治思想
  5. 串(KMP算法)
  6. 数组和广义表
  7. 树和二叉树
  8. 动态存储管理
  9. 查找
  10. 排序

目录

二 线性表 

2.3 线性表的链式表示

2.3.1 线性表的单链表存储结构(C 语言中用结构指针表示):

2.3.2 单链表的初始化

2.3.3 单链表-获取单链表的第i个元素的函数实现

2.3.4  单链表结点的插入​编辑

2.3.5  单链表结点的删除

2.3.6  malloc()和free()函数

2.3.7  头插法建立单链表

2.3.8  尾插法建立单链表

2.3.9  归并两个(有序)单链表

2.3.10  输出整个单链表

2.3.10  计算单链表的长度

2.3.11  修改单链表结点的值 

2.3.12  完整代码 + 测试结果


二 线性表 

        上节中,线性表的顺序存储结构特点是:逻辑关系上相邻的两个元素在物理位置上也相邻。它的弱点很明显,在进行插入和删除操作时,需要移动大量的元素。本节讨论链式存储结构,它不要求逻辑相邻的元素物理上也相邻,所以它没有顺序结构的弱点,但也失去了顺序表可以随机存储(在给定元素位置的情况下,顺序表可以在常数时间内(O(1)时间复杂度))的优点。

2.3 线性表的链式表示

        特点:用一组任意的存储单元存储线性表的数据元素(连续与否都可)。

        所以为了表示a_{i}和直接后继a_{i+1}之间的逻辑关系,除了存储a_{i}的信息,还需要存储直接后继a_{i+1}的信息(存储位置)。两部分组成a_{i}的存储映像,称为结点

        它包括两个域,数据域指针域(其中存储的信息成为指针或者)。n个结点(a_{i}(1\leq i\leq n))的存储印象,链结成一个链表,即为线性链表单链表

(a_{1},a_{2},...,a_{n})

        线性链表的存储必须从头指针(指示链表中第一个结点的存储位置)开始进行。由于最后一个元素没有直接后继,则线性链表最后一个节点的指针为NULL。

2.3.1 线性表的单链表存储结构(C 语言中用结构指针表示):
#include <stdio.h>
#include <stdlib.h>

//- - - - - 线性表的单链表存储结构 - - - - -

// 线性表的单链表存储结构体
typedef struct ListNode{
	int data;				// 数据域,存储节点的数据元素
	struct ListNode *next;	// 指针域,指向下一个节点的指针 next:结构体指针变量,指向结构体的地址
} ListNode, *LinkList;		// ListNode用于表示struct ListNode结构体,简化了结构体类型的引用
							// LinkList这个别名表示指向struct ListNode的结构体类型的指针,它
							// 使得可以直接使用LinkList来声明指向链表节点的指针变量

        假设L是单链表的头指针,它指向表中的第一个结点。若L为空(L=NULL),则表示线性表为空。单链表通常以一个特殊的结点作为头结点,头结点的数据与可以不存储任何信息,也可以存储线性表长度等附加信息,头结点的指针域指向第一个结点的指针。

        虽然单链表中的两个元素之间没有固定联系,但是每个元素的存储位置包含在前驱结点的信息中。所以我们有:假设p是指向线性表中第i个元素(结点a_{i})的指针,则p->next是指向i+1元素(结点a_{i+1})的指针。则有p->data = a_{i}p->next->data = a_{i+1}。所以单链表中,取得第i个元素,必须从头指针开始寻找,所以单链表是非随机存储的存储结构。下面是单链表的初始化获取单链表的第i个元素的函数实现。

2.3.2 单链表的初始化
// 初始化单链表(初始化为空链表)
void InitList(LinkList* L) {	// 链表接受一个指向指针LinkList的指针LinkList* L 这样可以在函数内部修改指针的值
	*L = (LinkList)malloc(sizeof(ListNode)); // *L是L指针变量的解引用,表示获取指针变量LinkList的值,指针变量
											 // LinkList存储的是struct ListNode的首地址
	// malloc函数,动态分配内存,接受一个参数,返回指向分配内存起始地址的指针。
	// (LinkList)类型甄嬛。它将malloc函数返回的通用指针 void *类型转化为LinkList类型(struct ListNode)的指针
	if (!(*L)) {
		printf("内存分配失败!\n");
		exit(-1);
	}
	(*L)->next = NULL;
}
2.3.3 单链表-获取单链表的第i个元素的函数实现
// 获取单链表的第i个元素
int GetElem(LinkList* L, int i) { // 链表接受一个指向指针LinkList的指针LinkList* L
	int j = 1; //计数器
	LinkList p = (*L)->next; // 初始化p指向第一个结点 其中L->next表示下一个结点的地址
	while (p && j < i) { //指针向后查找,直到p指向第i个元素,或p不存在
		p = p->next;
		j++;
	}
	if (!p || j > i) { //当p不存在时,j>i 有两种可能链表中元素的数量小于i或者i<=0
		printf("第%d个元素不存在!\n", i);
		exit(-1);
	}
	return p->data; // 返回结点的值
}

        在获取单链表的第i个元素的函数中,其基本操作为while循环中的循环条件p指针的存在比较i,j的大小,还有后移指针p。while循环中语句的频度与被查元素在表中的位置有关,若1\leq i\leq n,则频度为i-1(因为要编译到第i个元素的前一个结点),否则频度为n(如果i超出了有效范围(小于1或者大于n),那么就需要遍历整个链表直到最后一个节点,循环的频度就是n)。因此该算法的时间复杂度为O(n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值