线性表包括
顺序表、单链表、双向链表、循环链表
1. 线性表相关概念
线性表(Linear List)
是由n(n≥0)个具有相同特性(数据类型)的数据元素(结点)a1,a2,...,ai-1,ai,ai+1,...,an组成的有限序列。
L= (A1, A2, ... , Ai, Ai+1.…. , An)i (1≤i≤n)
a1为线性起点(起始结点),an为线性终点(终端结点)。对于每一个数据元素ai,ai-1为它的直接前驱,ai+1为它的直接后继。n为数据元素总个数,即表长。当n=0时,线性表为空表。
Ai 是线性表中的 “ 第 i 个” 元素线性表中的位序( 位序从1开始,数组下标从0开始 )
线性表按存储分类
不破坏数据的前后次序,将它们连续存储在内存空间中,按这样的存储方案称为顺序存储结构(简称顺序表)。
将所有数据分散存储在内存中,按这样的存储方案称为链式存储结构(简称链表)。
1.顺序表的操作见
https://blog.csdn.net/2301_80433738/article/details/139016821?spm=1001.2014.3001.5502
2.线性链表的一些认识和操作
关于线性链表的知识:结点(节点),头结点、头指针和首元结点
结点(Node):
链表中,每个数据元素都配有一个指针,结点由数据域和指针域构成。
typedef struct node {
int d; //数据域
struct node* next; //指针域
};
对数据域的定义;数据域是描述字段技术属性的集合,包括数据类型、长度、精度等
对指针域也类似;
数据域用来存储元素的值,指针域用来存放指针。数据结构中,通常将上图这样的整体称为结点。
头指针:始终指向链表中第一个结点的指针,通常用其来标识一个链表。头结点是链表中的首元结点之前,头指针之后的一个结点。是一个链表中的第一个结点,其数据域内用于存放空表标志和表长信息等。
头结点:某些场景中,为了方便解决问题,会故意在链表的开头放置一个空结点,这样的结点就称为头结点。也就是说,头结点是位于链表开头、数据域为空(不利用)的结点。
🥝注意(链表中头节点不一定有,而链表一定有头指针)
首元结点:指的是链表开头第一个存有数据的结点。
操作
定义节点数据结构
typedef struct node {
int d;
struct node* next;
};
输出显示线性链表
void prtList(node* head) //负责输出显示线性链表
{
cout << "当前链表的内容为:";
while (head != NULL) {
cout << head->d << ' ';
head = head->next;
}
cout << endl;
}
头插法创建并初始化一个长度为K的链表,(链表内容是自然数 )
void CreateListHead(node *head,int K)
{
//head为传入的头指针
//K为表长
head = NULL;
node* p;
for (int i = 1; i < K; i++) {
p = new node;
p->d = i;
p->next = head;
head = p;//head指向p结点 为下一个p(i+1)指向p做准备
}
逆转单链表(不带头节点)
例举 递归法和🚩头插法
头插法比较容易理解
node* invertList(node* head) //负责逆转链表的函数
{
if ( head==NULL||head->next ==NULL) {
return head;
}
node* n_head = invertList(head->next);
head->next->next = head;
head->next = NULL;
return n_head;
}
node* invertList(node* head) {
node* p = NULL, * nhead = NULL;
while (head != NULL) {
p = head; //指向 NULL 的指针变量 p 重新指向另一个 node结构类型的指针 head
head = head->next;
p->next = nhead;
nhead = p;
}
return nhead;
}
分析头插法: 先定义两个node*类型的指针 p 和 nhead(new_head)
令p重新指向head p现在代表head(旧); 然后head指向head->next代表的结点
获得新的head(新) 为下一次循环做准备;
p->next指向待传出的反转链表头指针( 此时p->next代表的是最开始head(旧)的head->next 由于头插法创建的单链表head->next指向的是最后一个结点;
到循环的最后一步前 nhead的第一个首元结点即为原列表的最后一个结点;
然后nhead指向p(可由图 此时p指向i+1即首元结点);
继续循环完成至head==NULL;
1,3行可观察到p始终指向最新的一个结点的前一个结点获取next为nhead链接做准备;
2,4行为下次循环做准备
熟悉这四行主要代码后多练习030;
合并两个单链表(不含头结点)
node* combineList(node* AH, node* BH) //负责合并链表
{
node* ch;//新链表(最终为合并的链表
node* r;
node* p = AH;
node* q = BH->next;
ch = BH, ch->next = NULL,r=ch;
//r代表ch开始为ch构建新链表
//ch->next=NULL 由于为头插法创建的BH BH的next指向最后一个结点
while (p != NULL && q != NULL) {
if (p->d > q->d) {
r->next = p; p = p->next;//p->d大于q->d则r接p p往下一个走 r往下一个NULL结点走;
r = r->next;
}
else {
r->next = q; q = q->next;//同上
r = r->next;
}
}
if (p != NULL)r->next = p;
if (q != NULL)r->next = q;
return ch;
}
未完