本篇文章总结数据结构题目中出现有关于链表的知识点。
包括链表的声明(两种结构体的创建方法),链表的创建(头插法和尾插法),单/双链表的节点插入(已知前节点/后节点),有序链表的合并等。
1. 链表的声明
此处包含结构体的创建,声明为结构体变量和结构体指针变量的区别。以及两种定义指针变量,为变量申请空间的方法malloc/free和new/delete。
(1)结构体的创建:创建的时候可以根据typedef的类型,创建结构体指针和结构体变量两种类型。
(2)结构体指针和结构体变量使用成员方式不同,分别为 . 和 ->;
(3)结构体指针需要申请空间(使用malloc和new),结构体变量不需要;
(4)定义时可定义指针,作为函数返回值,使用指针型返回值;
#include <iostream>
#include<malloc.h>
using namespace std;
typedef struct node{
int val;
node *next;
}Node,*Link;
typedef struct{
string name;
int age;
}student,*S;
int main()
{
student s1;//定义结构体变量,使用.,且不需要申请空间
s1.name="Tom";
s1.age=13;
Link n1,n2;//定义结构体指针,申请空间
n1=new Node;
n2=(Link)malloc(sizeof(Node));
n1->val=1;
n1->next=n2;
n2->val=2;
n2->next=NULL;
delete []n1;
free(n2);
return 0;
}
2. 链表的创建
头插法和尾插法,三步和两步。
(1)头插法:两步,首先newNode->next=head->next,接着head->next=newNode
//使用头插法建立链表
void Creat_LinkList_HeadInsertion(ListNode *phead,int n){
ListNode *p=phead;
for(int i=0;i<n;i++)
{
ListNode *newNode=new ListNode;
cin>>newNode->value;
newNode->next=p->next;
p->next=newNode;
}
}
(2)尾插法:三步,首先newNode->next=NULL,其次p->next=newNode,最后p=p->next,p为移动的尾节点。
//使用尾插法建立链表
void Creat_LinkList(ListNode *phead,int n){
ListNode *p=phead;
for(int i=0;i<n;i++)
{
ListNode *newNode=new ListNode;
cin>>newNode->value;
newNode->next=NULL;
p->next=newNode;
p=newNode;
}
}
3. 双向链表的创建
一般使用尾插法。所以依然是三步,不过加了对前指针pre的处理。首先对输入新节点初始化,即newNode->next=NULL,newNode->pre=NULL;其次插入进链表:newNode->next=p->next,p->next=newNode,加上一句newNode->pre=p;最后移动尾节点p=p->next。
同时,如果是双向循环链表还要将首尾相连,即最后p->next=head,head->pre=p。
//创建双向链表
void Create_double_LinkList(LinkNode *head,int m,char *a)
{
LinkNode *p=head;
for(int i=0;i<m;i++)
{
LinkNode *node=new LinkNode;
node->value=a[i];
node->freq=0;
node->next=NULL;
p->next=node;
node->pre=p;
p=p->next;
}
p->next=head;//如果是循环链表就要加这一句
head->pre=p;
}
4. 链表的节点插入
包括已知前结点的插入和已知后节点的插入,以及双向链表中节点的插入。
(1)已知前节点:两步
//已知前节点:直接插入节点
newNode-next=p->next;
newNode->value=X;
p->next=newNode;
(2)已知后节点:将此节点值记录下来,新节点值赋给此节点,然后插入带有此节点的值的新节点到此节点后面,变成了已知前向节点的插入
//已知后节点:先保存值,再插入节点
newNode->value=p->value;
p->value=X;
newNode-next=p->next;
p->next=newNode;
(3)双向链表:四步,首先赋给本节点的后指向,其次改变后节点的前指向,接着改变本节点的前指向和前节点的后指向(这两个不分顺序)。
//将newNode插入p的后面
newNode->next=p->next;
p->next->pre=newNode;
p->next=newNode;
newNode->pre=p;
5. 链表中交换节点元素的次序
先取下本节点:一步将本节点的next赋给前节点的next即可。然后普通插入。
6. 有序链表的合并
类比于三元组存储矩阵,实现矩阵相加的的思想。
见例题:(62条消息) 【数据结构】NOJ004—单链表的归并_杨的博客-CSDN博客
(1)对于遍历两个有序链表,直接遍历一次即可;
(2)且不用申请新的节点空间,直接指向该节点,然后节点同时后移。类似于尾插法,p后移一位即可;
(3)掌握剩余链表的简洁插入法:pc->next=(pa==NULL?pb: pa)
void Merging_Linklist(LinkNode *headA,LinkNode *headB,LinkNode *headC)//归并链表
{
LinkNode *pa=headA->next,*pb=headB->next,*pc=headC;
while(pa!=NULL&&pb!=NULL)
{
if(pa->value<=pb->value)
{
pc->next=pb;
pc=pc->next;
pb=pb->next;
}
else
{
pc->next=pa;
pc=pc->next;
pa=pa->next;
}
}
pc->next=(pa==NULL?pb:pa);//最后剩余的直接指向
}