线性表是最常用的一种数据结构,简而言之,它是n个数据元素的有限序列,具有代表性像数组和链表。
一.线性表的顺序存储结构
线性表的顺序存储结构是指用一段地址连续的存储单元依次存储线性表的顺序单元,也是说开辟的内存空间是一片连续的地址空间,C语言中可以使用一维数组来来实现顺序存储空间。
一般需要以下几个属性来描述数组:
- 存储空间的存储位置,例如数组data[MAXSIZE];data就是存储位置;
- 最大存储空间是MAXSIZE;
- 线性表长度是data数据里面的数据元素个数。
二.线性表的链式存储结构
线性表的链式存储结构是指用一段存储单元存储线性表的数据元素,这组存储单元可以是连续的也可以是不连续的。
2.1 链表的结点结构
链表中的每一个节点不仅存有数据元素还存有后继节点的地址指针,我们存数据元素的域称为数据域,把存后继节点的域称为指针域,如下图所示。
链表第一个节点的存储的位置叫做头指针,线性表的第一个节点和最后一个节点
头指针和头节点的异同:
2.1.1 头指针
- 头指针是链表指向第一个节点的指针,若有头节点,则是指向头节点的指针;
- 无论链表是否为空,头指针不会为空;
2.1.2 头节点
- 处理起来方便。例如,对在第一元素结点前插入结点和删除第一结点操作与其他结点的操作就统一了。(通过判断头节点的指针域是否为空,来判断是否为空表)
- 无论链表是否为空,其头指针是指向头结点的非空指针,因此空表和非空表的处理也就统一了。
2.2 单链表
带有头结点的单链表如下图
2.2.1 单链表
1.单链表的结构体类型
typedef struct List
{
Stu data;
struct List *next;
}ListNode;
2.空链表的创建
ListNode * create_list(void)
{
ListNode *head; //定义头结点
head = (ListNode *)malloc(sizeof(ListNode)); //为头结点分配空间
head->next = NULL; //将指针域置空
return head;
}
3判断链表是否为空
Status list_is_empty(ListNode *list)
{
if(list->next == NULL) // 判读头结点指针域是否为空
{
printf("list is emtpy");
return LIST_OK;
}
return LIST_ERR;
}
4 链表打印
void print_list(ListNode * list)
{
ListNode *p = (ListNode *)malloc(sizeof(ListNode));
p->next = list->next;
while(p->next !=NULL)
{
p = p->next; //节点后移
printf("id = %d ,score = %f, name = %s \n",p->data.id,p->data.score,p->data.name);
}
printf("\n");
}
5.插入节点
int insert_list_end(ListNode * list,Stu data)
{
ListNode * node = create_node(data); //创建节点
ListNode * end = NULL; //定义一个尾节点
end = list; //尾节点指向头结点
while(end->next != NULL)
{
end = end->next; //判断是否尾节点,
}
//node->data = data;
end->next = node; //插入的节点地址放入end的指针域中
end = node; //插入结点变成表尾节点
end->next = NULL; //end指针域为空
}
6 按id删除节点
Status delete_node_for_id(ListNode *list,int id)
{
ListNode *delete_node;
ListNode *pre_node;
if(list_is_empty(list) == LIST_OK ) //表空误无除数据
{
return LIST_ERR;
}
delete_node = list;
//pre_node = list;
//printf("id=%d",delete_node->data.id);
while( delete_node->data.id != id ) //遍历要删除的节点
{
pre_node = delete_node; //删除节点的前继节点
delete_node = delete_node ->next; //节点后移
//printf("id=%d",delete_node->data.id);
if(delete_node->next == NULL) //没有找到要删除的节点
{
printf("find id error \n");
return LIST_ERR;
}
}
//pre_node = delete_node;
pre_node->next = delete_node->next; //将后继节点的地址放到前面节点的指针域种
free(delete_node);
}
7 清空链表
Status clear_list(ListNode *list)
{
ListNode * p = list ->next;
ListNode *q;
if(list_is_empty == LIST_OK)
{
return LIST_OK;
}
while(p->next !=NULL)
{
q = p->next;
free(p);
p = q;
}
list->next = NULL;
return LIST_OK;
}
2.2.2 代码示例
示例是创建一个数据为学生类的单链表,其中包链表创建,节点的创建,链表的是否为空,链表的插入,链表的删除以及清空链表程序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum Status
{
LIST_OK = 0,
LIST_ERR
}Status;
/*定义一个学生类的结构体包含编号、名字、分数*/
typedef struct Stu
{
int id;
float score;
char* name;
}Stu;
/*定义单链表数据类型结构体*/
typedef struct List
{
Stu data;
struct List *next;
}ListNode;
//typedf struct NODE ListNode;
/*建立一个空表*/
ListNode * create_list(void)
{
ListNode *head;
head = (ListNode *)malloc(sizeof(ListNode));
head->next = NULL;
return head;
}
/*建立一个节点*/
ListNode * create_node(Stu student)
{
ListNode *node;
node = (ListNode *)malloc(sizeof(ListNode));
//memcpy(node->data,&student,sizeof(Stu));
node->data = student;
node->next = NULL;
return node;
}
/*打印链表*/
void print_list(ListNode * list)
{
ListNode *p = (ListNode *)malloc(sizeof(ListNode));
p->next = list->next;
while(p->next !=NULL)
{
p = p->next;
printf("id = %d ,score = %f, name = %s \n",p->data.id,p->data.score,p->data.name);
}
printf("\n");
}
/*判断是否为空*/
Status list_is_empty(ListNode *list)
{
if(list->next == NULL)
{
printf("list is emtpy");
return LIST_OK;
}
return LIST_ERR;
}
/*尾插法插入数据*/
int insert_list_end(ListNode * list,Stu data)
{
ListNode * node = create_node(data);
ListNode * end = NULL;
end = list;
while(end->next != NULL)
{
end = end->next;
}
//node->data = data;
end->next = node;
end = node;
end->next = NULL;
}
/*按照 id 删除 数据*/
Status delete_node_for_id(ListNode *list,int id)
{
ListNode *delete_node;
ListNode *pre_node;
if(list_is_empty(list) == LIST_OK )
{
return LIST_ERR;
}
delete_node = list;
//pre_node = list;
//printf("id=%d",delete_node->data.id);
while( delete_node->data.id != id )
{
pre_node = delete_node;
delete_node = delete_node ->next;
//printf("id=%d",delete_node->data.id);
if(delete_node->next == NULL)
{
printf("find id error \n");
return LIST_ERR;
}
}
//pre_node = delete_node;
pre_node->next = delete_node->next;
free(delete_node);
}
/**/
/*将表清空*/
Status clear_list(ListNode *list)
{
ListNode * p = list ->next;
ListNode *q;
if(list_is_empty == LIST_OK)
{
return LIST_OK;
}
while(p->next !=NULL)
{
q = p->next;
free(p);
p = q;
}
list->next = NULL;
return LIST_OK;
}
int main(int argc, char * argv [ ])
{
ListNode *list;
/*创建两个学生信息*/
Stu stu1={1,95.0,"zhangsan"};
Stu stu2={2,92.0,"lisi"};
//ListNode * head_node;
/*创建一个空链表*/
list = create_list();
/*尾插法插入链表*/
insert_list_end(list,stu1);
insert_list_end(list,stu2);
/*打印链表*/
print_list(list);
/*删除ID为1的节点*/
delete_node_for_id(list,1);
/*打印链表*/
print_list(list);
/*清空链表*/
if(clear_list(list) == LIST_OK);
printf("clear list success.\n");
/*打印链表*/
print_list(list);
return 0;
}
运行结果: