线性表是一种常用的数据结构,分为顺序表和链表;
正常方式定义一个数组时,计算机开辟一块连续的地址来存放给定长度的数组;而链表由若干个节点构成(一个节点代表一个元素),且节点在内存中的储存位置通常不连续,两个节点之间一般通过一个指针来从一个节点指向另一个节点,链表的节点由数据域和指针域构成;
节点定义:
struct node
{
int data;//数据域;
node *next;//指针域;
}
将链表是否存在头节点分为带头节点的链表和不带头节点的链表。头节点一般称head其数据域不存放任何内容而指针域next指向第一个数据域有内容的节点(第一个节点)。
如何在在每次需要使用新节点时临时分配相应大小的内存空间给新节点呢?
1.C语言中的 malloc 函数;
2.C++ 中的 new 函数;
1.malloc 函数
头文件 stdlib.h 用于申请动态内存函数 其返回类型是申请的同变量类型的指针 :
typename p = (typename)malloc(sizeof(typename));
申请一个int型变量和一个node型结构体变量:
int *p = (int *)malloc( sizeof(int) );
node *p =(node *)malloc( sizeof(node) );
注:node型结构体变量为例:以需要申请的内存空间大小( sizeof(node) )为malloc函数的参数,这样malloc函数就会向内存申请一块大小为sizeof(node) 的空间,并且返回指向这块空间 的指针,这时的指针是一个未确定类型的指针void * 所以需要强制类型转换 然后通过指针 p 来访问这块node类型大小的内存空间 ,如果申请失败返回NULL;(当申请较大的动态数组时会失败 :int *p = (int )malloc( 100000 sizeof(int) );
2.new 运算符
用法:
typename *p = new typename;
同样申请哟个int 型变量和 node型结构体变量:
int *p = new int;
node *p = new node;
new 比malloc的优点就在于一是简洁 二是如果申请内存失败,会启动C++ 异常机制处理而不是返回NULL。
注意:
在使用malloc和new 之后得自己释放内存不然会造成内存泄漏;
(1)malloc free:
free 用来释放malloc函数 头文件stdlib.h 下
int *p = (int *)malloc( sizeof(int) );
free§ ;
(2)new delete:
int *p = new int ;
delete§;
//
一. 创建链表:
struct node //链表节点;
{
int data;
node *next;
};
//创建链表;
node * create(int array[])
{
node *p, *pre, *head;//pre保存当前节点的前驱节点,head 为头节点;
head = new node;//创建头节点;
head->next = NULL;//头节点不需要数据域,指针初始化为NULL;
pre = head;//记录pre为head;
for(int i = 0; i < 5; i++)
{
p = new node;//创建新节点;
//将array[i]赋给新建的节点作为数据域,也可以scanf输入;
p->data = array[i];
p->next = NULL;//新节点的指针域设为NULL因为链表结束的标志是最后的节点的指针域为NULL;
pre->next = p;//前驱节点的指针域设为当前的新建节点的地址;
pre = p; //把pre设为p,作为下一个节点的前驱节点;
}
return head;//返回头节点指针;
}
int main(void)
{
int array[5] = {3, 4, 2, 1, 5};
node *L = create(array);//新建链表,返回的头指针head赋给L;
L = L->next;//从第一个节点开始有数据;
while(L != NULL)
{
printf("%d", L->next);
L = L->next;
}
return 0;
}
二. 查找元素
判断一条链表中X 的个数
int search( node * head, int X)
{
int count = 0;//计数器;
node *p = head->next;//从第一节点开始;
while(p != NULL)
{
if(p->next == X)
{
count ++;
}
p = p->next;
}
return count;
}
三.插入元素
例如5->3->4->2->1在第三个位置插入6 :指完成插入操作以后第三个位置上的数据是6
先将元素6 的指针域指向元素4所在节点的地址;
再将元素3所在节点的指针域next指向元素6的所在的节点地址;
void insert(node *head, int pos, int X)//将X插入以head为头节点的链表的第pos 个位置上;
{
node *p = head;
for(int i = 0; i < pos-1; i++)
{
p = p->next;//pos-1为了到插入位置的前一个节点;
}
node *q = new node;//新建节点;
q->data = X;//新建节点数据域为X;
q->next = p-next;新节的next指向原本前一个节点要指向的next;
p->next = q; //前一个节点next指向新节点;
}
四.删除节点
要删除链表上所有值为X的数,如一个链表5->3->4->2->1删除4变为5->3->2->1;
void delete(node *head, int X)
{
node *p = head->next;//p从第一个节点开始;
node *pre = head;//pre始终保存p的前驱节点的指针;
while( p != NULL)
{
if(p->next == X)
{
pre->next = p->next;
delete(p);
p = pre->next;
}
}
}
五.链表的销毁和清零
1.销毁:
void destroyList(node *head)
{
node *p = new node;
if(head == NULL)
{
return 0;
}
while(head)
{
p = head->next;
delete(head);
head = p;
}
return;
}
2.清零:
void clearlist(node *head)
{
node *p, *q;
if(head == NULL)
{
return ;
}
p = head->next;
while(p != NULL)
{
q = p->next;
delete(p);
p = q;
}
head->next = NULL;
return ;
}
注:在使用malloc 和new 之后必须使用free 和delete 释放 并且将指针指向NULL避免出现内存泄漏和野指针的出现