什么是链表
动态进行存储分配的一种结构,可以根据需要开辟内存单元。
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
链表的优势就是增删非常容易。
链表图解
下面通过代码直接创建一个链表,一目了然。
#include <stdio.h>
#include <stdlib.h>
//链表中的一个节点.
typedef struct node
{
int data; //数据
struct node* next;//指向下一个节点.
}Node,*pNode;
Node head; //初始化成0;全局变量没有初始化则保持在bss段
pNode pHead = &head;//定义头指针
//在链表的末尾添加数据.
//把DATA存入链表最后一个节点,然后把整个节点个数返回
int insert_end(int DATA)
{
//1内存空间的申请(造车厢)
pNode pnew = (struct node*)malloc(sizeof(Node));
if (NULL == pnew)//内存申请失败
{
printf("申请失败\n");//容错处理.
return 0;
}
//2.数据的初始化.(放人到车上)
pnew->data = DATA;
pnew->next = NULL;//链条放在地上防止静电
//3连起来
pNode ptemp = pHead;
while (ptemp->next) //最后一个结点的next会等于NULL
{
ptemp = ptemp->next;//指向下一个节点
}
ptemp->next = pnew;//最后一个节点的next指针指向pnew,等价于把pnew链接到整个链表的末尾.
return ++pHead->data;//头结点数据记录了整个节点个数
}
//在头结点的下一个节点添加数据.头插法.
int insert_head(int DATA)
{
//1内存空间的申请(造车厢)
pNode pnew = (struct node*)malloc(sizeof(Node));
if (NULL == pnew)//内存申请失败
{
printf("申请失败\n");//容错处理.
return 0;
}
//2.数据的初始化.(放人到车上)
pnew->data = DATA;
pnew->next = NULL;//链条放在地上防止静电
//3.把新节点链接到链表
pnew->next = pHead->next;
//4.把头结点的next指针连接到新节点
pHead->next = pnew;
//5.头指针数据加1.
return ++pHead->data;
}
//显示整个链表
void show()
{
//1用一个临时指针指向于链表头
pNode p = pHead;
while (p->next)
{
printf("%d-> ", p->data);
p = p->next; //p++错误
}
printf("%d->", p->data);
printf("NULL\n");
}
//把链表中第一个数据为da的节点修改成DATA.
void change(int da,int DATA)
{
pNode p = pHead;
while (p->next)
{
if (p->data == da)
{
p->data = DATA;
//break;如果只修改其中第一个则加上break;
}
p = p->next;
}
if (p->data == da) //最后一个节点需要单独判断
{
p->data = DATA;
}
}
//查找da数据是否在链表中存在,如果存在则返回位置.
int find(int da)
{
int temp = 0;
pNode p = pHead->next; //pNode p指向头节点的下节点
while (p->next) //遍历整个链表
{
temp++;
if (p->data == da) //找到了相应的数据
{
return temp;
}
p = p->next;
}
if (p->data == da) //在尾部找到了对应的数据
{
return ++temp;
}
return -1;//返回错误
}
//主函数
int main()
{
insert_head(10);
insert_head(20);
insert_head(50);
insert_head(30);
insert_head(50);
insert_head(40);
insert_head(50);
insert_end(123);
show();
change(50, 666);
printf("查找到的位置是%d\n",find(1));
show();
return 0;
双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
代码实现双向链表
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node* prev; //当前节点的前驱节点
struct node* next; //当前节点的后继节点
}Node,*Pnode;
//链表初始化,创建链表
/*****只可以在当前文件调用,加static
作用: 创建一个节点,然后把节点指针返回.
参数: 第一个:需要保存的数据.
第二个:当前节点的上一个节点指针
第三个:当前节点的下一个节点指针
返回:创建的新的节点指针
*/
static Pnode createNode(int DATA,Pnode pr,Pnode nx)
{
Pnode pnew = (Pnode)malloc(sizeof(Node));
pnew->data = DATA;
pnew->next = nx;
pnew->prev = pr;
return pnew;
}
typedef struct list{
Pnode pHead; //整个链表的头部
Pnode pTail; //整个链表的尾部
}List,*pList;
//初始化工作.
void init(pList ls)
{
ls->pHead = NULL;
ls->pTail = NULL;
}
//在末尾插入,ptail后面插.
void insert_end(pList ls,int DATA)
{
//创建一个节点.封装到一个函数中
// 同时把ptail移动到最后一个位置
ls->pTail = createNode(DATA,ls->pTail,NULL);
if (ls->pTail->prev)//有多个节点的情况
{
ls->pTail->prev->next = ls->pTail; //(难点)
}
else//只有一个节点的情况.
{
ls->pHead = ls->pTail;
}
}
// 得到链表节点个数
int GetSize(pList ls)
{
int size = 0;
for (Pnode p = ls->pHead; p;p = p->next){
++size;
}
return size;
}
int main()
{
List list;
//pList ls = mlloc;
init(&list);
return 0;
}