1.链表的概念
链表(Linked List)是一种常见的数据结构,用于存储和组织数据。它由一系列节点(Node)组成,每个节点包含数据和指向下一个节点的指针。
如图所示,是一个节点(Node)的组成,在数据域(Date)包含了数据,在指针域(Next)包含了指向下一个节点(Node)的指针。
链表的特点是节点之间通过指针相互连接,形成一个链式结构。相比于数组,链表的大小可以动态地增加或减少,因为它不需要预先分配一块连续的内存空间。它的存储思想是用一组任意(即不连续 零散分布)的存储单元存放线性表的元素,链表可以根据需要灵活地插入、删除和修改节点。
2.单链表的实现
1.创建一个单链表节点
typedef struct node
{
DateType data;
struct node *next;
}Node,*Link
p = (Link)malloc(sizeof(Node));
头指针:指向第一个节点的地址。
尾标志:终端节点的指针域为空。
这是一个空表 数据域和指针域都为空
如何将空表与非空表统一呢?
头节点:在单链表的第一个元素节点之前附设一个类型相同的节点,以便空表和非空表处理统一。
2.单链表的遍历操作
void displayNode(Link head)
{
p = head->next;
while(p!= NULL)
{
printf("%d ",p->date);
p = p->next;
}
}
p指针首先指向头节点的next,next存放了下一个节点的地址。p->data时,即读出了data1的数据,依此类推。
3.求单链表的元素个数
int length (Link head)
{
p = head->next;
count = 0;
while(p! = NULL)
{
p = p->next;
count++;
}
return count;
}
与遍历操作一样,在遍历的时候加入count进行计数,然后返回。
4.单链表的查找操作
int queryNode(Link head,DataType x)
{
p = head->next;
while(p!=NULL)
{
if(p->data == x)
{
printf(data);
return true;
}
}
reture false;
}
移动指针p遍历链表,当读出的数据date等于x时,打印数据并返回true;
当遍历完所有数据都未能找到时,则返回false。
5.单链表的插入操作
bool insertNode(Link head, int i,DataType x)
{
p = head;
count = 0;//利用count来移动指针
while(p!=NULL && count < i-1)//如果查询到空指针退出循环 当指针移动到所需要的位置也退出循环
{
p = p->next;
count++;
}
if(p == NULL)
{
return false;
}
else
{
node = (Link)malloc(sizeof(Node));
node->data = x;
node->next = p->next;//node的指针域指向原本p的指向的节点
p->next = node;//p的指针域指向node
return true;
}
6.创建一个单链表
6.1头插法创建一个单链表
头插法:将待插入节点插在头节点后面(就是头节点的指针域存放节点新节点node的地址 新节点node存放head->next的地址 此时如果是一个数组,则数组存放在链表里的值则为反序的)
Link newList(DataType a[],int n)
{
head = (Link)malloc(sizeof(Node));//创建一个头节点
head->next = NULL;
for(i=0;i<n;i++)
{
node = (Link)malloc(sizeof(Node));
node->data = a[i];
node->next = head->next;
head->next = node;
}
return head;
}
程序流程如图所示
6.2 尾插法创建一个单链表
尾插法:将待插入节点插在终端节点的后面
初始化 创建一个头节点时
此时头节点和尾节点为同一个节点
Link newList(DataType a[],int n)
{
head = (Link)malloc(sizeof(Node))
head->next = NULL;
rear = head;
for(i=0;i<n;i++)
{
node = (Link)malloc(sizeof(Node));
node->data = a[i];
rear->next = node;
rear = node;
}
rear->next = NULL;
return head;
}
7.单链表节点的删除
查找节点的过程中,如何保证指针p和q一前一后呢?
q = p;
p = p->next;
bool deleteNode(Link head,DataType x)
{
if(head == NULL||head->next == NULL)//判断链表是否为空表
{
return false;
}
p = head->next;
q = head;
while(p!= NULL)
{
if(p->data == x)
{
q->next = p->next;
free(p);
return true;
}
else
{
q = p;
p = p->next;
}
}
return false;
}
3.循环链表的实现
问:从单链表中某节点p出发如何找到其前驱?
将单链表的首尾相接,将终端节点的指针域由空指针改为指向头节点,构成单循环链表,简称循环链表。
循环链表的特点
循环链表没有明显的尾端 如何避免死循环
与单链表不同 单链表的循环结束条件为p!=NULL 此时应该修改为p!=head
4.双向链表
双向链表:在单链表的每个节点中再设置一个指向其前驱节点的指针域。
用循环链表的方式找到p的前驱,在时间上需要更多的时间。
用双向链表的方式可以快速求得p的前驱,相应的需要占据更大的空间。
data:数据域 存储数据元素
prior:指针域 存储该节点的前驱节点的地址
next:指针域 存储该节点的后继节点地址