首先来谈谈链式存储结构:
(1)特点:用一组任意的存储单元存储线性表中的数据元素;这组存储单元可以是连续的,也可以是不连续的;每个数据元素除了存储数据外,还要存储前驱、后继元素的地址。
1、单链表:n个节点按链式存储结构存储,每一个结点只包含一个指针域。下面来分享一下链表基本功能和C语言中的实现。
(1)线性表的单链表存储结构:
typedef int DataType;
typedef struct Node
{
DataType data;//数据域
struct Node *next;//指针域
}Node;
(2)获取指定位置的元素:
Node* getptr(Node *head, int pos)
{
Node *p = head;//p与head指向同一个位置
if(p == NULL || pos == 0)//p为空的时候,代表链表为空
{
//当pos为0时就是head的指向,所以返回head
return head;//返回一个空指针
}
for(int i = 0; p && i < pos; i++ )//必须要加上p&&这句话防止p为空指针
{
p = p->next;
}
return p;
}
(3)获取单链表中结点个数:
int getSize(Node *head)
{
int size = 0;
Node *p = head;
while(p)//判断P是否为空
{
size++;
p = p->next;
}
return size;
}
(4)单链表中插入
/*********************************************************
* head:为二级指针
* position:插入的位置
* d:数据
*********************************************************/
bool insert(Node **head, int position, DataType d)
{
//判断是否可以插入
if(position < 0 || position > getSize(*head))//先判断是否正确
{
return false;
}
//分配一个要插入数据的空间
Node *node = (Nodee *)malloc(sizeof(Node));
node->data = d;
node->next = NULL;//令当前指针指向为空
if(position == 0)
{
//表示在头部或者在空链表中插入
node->next = *head;
*head = node;
return true;
}
//表示在任何位置插入数据
Node *p = getptr(*head, position - 1);//获取前面一个数据的地址
//进行插入操作
Node *r = p->next;
node->next = r;
p->next = node;
return true;
}
(5)单链表的删除:
/******************************************************
* pos 为删除的位置
******************************************************/
bool erase(Node **head, int pos)
{
//判断删除的位置是否正确
if(pos < 0 || pos >= getSize(*head))
{
return false;
}
//删除头结点
if(pos == 0)
{
*head = (*head)->next;//将指向他的指针释放
free(p);
p = NULL;//这一句话可以不要,但是这个是一个好习惯
return true;
}
//删除中间和最后的结点
p = getptr(*head, pos - 1);
Node *q = p->next;
p->next = q->next;
free(q);
q = NULL;//好习惯,如果没有写可能在调试时会崩溃
return true;
}
(6)两个线性表的合并
/****************************************************
* 通过找到第一个链表的尾指针,将尾指针指向第二个链表的头指针来实现
* 两个链表的合并
****************************************************/
void union(Node *a, Node *b)
{
Node *p = a;
while(p->next)
{
p = p->next;
}
p->next = b;
}
(7)将线性表倒置:
/**********************************************************
* head:为链表的头指针
**********************************************************/
void reverse(Node **head)
{
Node *p = *head;
Node *q = p->next;
if(q == NULL)
{
return;
}
Node *r = q->next;
if(p == *head)
{
p->next = NULL;
}
while(true)
{
q->next = p;
if(r == NULL)
{
*head = q;
break;
}
else
{
p = q;
q = r;
r = r->next;
}
}
}
(8)线性表的遍历:
void print(DataType d)
{
printf("%d\n", d);
}
// 使用函数指针的好处:当函数不是执行打印操作时可以随时改变函数的功能。
void trave(Node *head, void (*fun)(DataType))
{
Node *p = head;
while(p)
{
fun(p->data);
p = p->next;
}
}
主函数的调用:
void main(void)
{
Node *head = NULL;
//...
Node *p = getptr(head, 3);//获取3中的元素
int Len = getSize(head);//获取结点个数
insert(&head, 0, 10);//在头插入
insert(&head, 3, 5);//在任意位置插入
//删除代码示例
erase(&head, 0);//删除头结点
erase(&head, 1);//删除中间的结点
trave(head, print);
}