目录
一、数据结构的基本概念
二、顺序表与链表
2.1顺序表创建及算法
2.1.1顺序表的构建(以学生成绩管理为例)
//数据类型
typedef struct stu
{
char name[20];
unsigned char age;
unsigned short sco;
}Stu_t;
//顺序表数据类型
typedef struct list
{
Stu_t list[N]; //顺序表结构
unsigned index; //用于记录顺序表使用情况(0~N)
}Seqlist_t;
2.1.2顺序表的创建 (构建函数)
//创建顺序表
Seqlist_t *create_list(void){
Seqlist_t *L = (Seqlist_t *)malloc(sizeof(Seqlist_t)); //申请堆区空间
if (NULL == L)
{
puts("创建顺序表失败");
exit -1;
}
memset(L,0,sizeof(Seqlist_t)); //初始化顺序表
L->index = 0;
return L;
}
2.1.3顺序表内成员的插入(构建函数)
顺序表中任意位置插入成员
// 任意位置插入数据
int insert_data(Seqlist_t *L,unsigned pos,Stu_t data){
//健壮性判断
if (NULL == L)
{
puts("传参为空");
return -1;
}
if (N == L->index)
{
puts("表已满 插入失败");
return -1;
}
if (pos > L->index)
{
puts("插入位置不合理");
printf("位置范围为:0<=pos<%d\n",L->index);
return -1;
}
int i = 0;
for (i = L->index; i > pos; i--)
{
L->list[i] = L->list[i-1]; //需要将表中插入位置及之后的数据整体向后移动
}
L->list[pos] = data; //给所需要插入的位置重新赋值
L->index++; //顺序表有效成员个数加1
return 0;
}
2.1.4顺序表内成员的删除(构建函数)
//任意位置删除数据
int delete_data(Seqlist_t *L,int pos){
//健壮性判断
if (NULL == L)
{
puts("传参为空");
return -1;
}
if (0 == L->index)
{
puts("表空 删除失败");
return -1;
}
if (pos >= L->index)
{
puts("删除位置不合理");
printf("位置范围为:0<=pos<%d\n",L->index-1);
return -1;
}
int i = 0;
for (i = pos; i < L->index-1; i++)
{
L->list[i] = L->list[i+1]; //将所需要删除位置之后的所有成员向前移动
//整体向前覆盖一个位置
}
--L->index; //顺序表有效成员个数减1
return 0;
}
2.1.5顺序表内成员数据修改(构建函数)
//去除重名学生元素
int del_same_data(Seqlist_t *L);
//查找数据(根据姓名)
int find_data(Seqlist_t *L,char *f_name);
//修改数据(根据姓名)
int modify_data(Seqlist_t *L,char *f_name,Stu_t data);
//去除重名学生元素
int del_same_data(Seqlist_t *L){
//健壮性判断
if (NULL == L)
{
puts("传参为空");
return -1;
}
if (0 == L->index)
{
puts("表空 操作失败");
return -1;
}
if (1 == L->index)
{
puts("只有一个成员,无重名");
return -1;
}
int i = 0;
int j = 0;
int num = L->index;
for (i = 0; i < L->index; i++)
{
for (j = i+1; j < L->index; j++)
{
if (0==strcmp(L->list[i].name,L->list[j].name))
{
delete_data(L,j);
j--;
}
}
}
if (num == L->index)
{
puts("无重名");
}
return 0;
}
//查找数据(根据姓名)
int find_data(Seqlist_t *L,char *f_name){
//健壮性判断
if (NULL == L || NULL == f_name)
{
puts("传参为空");
return -1;
}
int i = 0;
Stu_t temp = L->list[i];
while (0 != strcmp(f_name,temp.name))
{
temp = L->list[++i];
if (i >= L->index)
{
puts("未找到该成员");
return -1;
}
}
printf("检索成功->姓名为:%-10s 年龄为:%-5d 成绩为:%-5d\n",\
L->list[i].name,L->list[i].age,L->list[i].sco);
putchar(10);
return 0;
}
//修改数据(根据姓名)
int modify_data(Seqlist_t *L,char *f_name,Stu_t data){
//健壮性判断
if (NULL == L || NULL == f_name)
{
puts("传参为空");
return -1;
}else if(0 == L->index)
{
puts("表空 操作失败");
return -1;
}
int i = 0;
Stu_t temp = L->list[i];
while (0 != strcmp(f_name,temp.name))
{
temp = L->list[++i];
if (i >= L->index)
{
puts("未找到该成员");
return -1;
}
}
printf("检索成功->姓名为:%-10s 年龄为:%-5d 成绩为:%-5d\n",\
L->list[i].name,L->list[i].age,L->list[i].sco
);
L->list[i] = data;
puts("修改成功!");
return 0;
}
2.1.6.排序 (构建函数)
//根据成绩排序
int sort_list(Seqlist_t *L);
//遍历顺序表
int show_list(Seqlist_t *L);
//根据成绩排序
int sort_list(Seqlist_t *L){
//健壮性判断
if (NULL == L)
{
puts("传参为空");
return -1;
}
if (0 == L->index)
{
puts("表空 排序失败");
return -1;
}
if (1 == L->index)
{
puts("只有一个成员,无需排序");
return -1;
}
int flag = 0; //采用标志位的方式降低冒泡排序的时间复杂度
for (int i = 0; i < L->index-1; i++)
{
for (int j = 0; j < L->index-1-i; j++)
{
if (L->list[j].sco > L->list[j+1].sco)
{
flag = 1;
Stu_t temp;
temp = L->list[j];
L->list[j] = L->list[j+1];
L->list[j+1] = temp;
}
}
if(0 == flag)
break;
}
return 0;
}
//遍历顺序表
int show_list(Seqlist_t *L){
//健壮性判断
if (NULL == L)
{
puts("传参为空");
return -1;
}
if (0 == L->index)
{
puts("表为空 遍历失败");
return -1;
}
for (int i = 0; i < L->index; i++)
{
printf(" 姓名为:%-10s 年龄为:%-5d 成绩为:%-5d\n",\
L->list[i].name,L->list[i].age,L->list[i].sco
);
}
return 0;
}
2.1.7顺序表的释放
//释放顺序表
int free_list(Seqlist_t **L){
//健壮性判断
if (NULL == L || NULL == *L)
{
puts("传参为空");
return -1;
}
free(*L);
*L = NULL;
return 0;
}
2.2有头单链表的创建及算法
2.2.1链表的构建
//数据结构体
typedef int data_t;
//链表结构体(成员结构体)
typedef struct node
{
data_t data;
struct node *next;
}Node_t;
2.1.2链表的创建(构建函数)
Node_t *create_list(void){
Node_t *L = (Node_t *)malloc(sizeof(Node_t));
if (NULL == L)
{
puts("<<创建链表失败/创建结点失败>>");
exit -1;
}
memset(L,0,sizeof(Node_t));
L->next = NULL;
return L;
}
2.1.3链表成员的插入(构建函数)
单链表的插入方式
//头插法
int head_insert(Node_t *L,data_t data);
//尾插法
int tail_insert(Node_t *L,data_t data);
//任意位置插入
int pos_insert(Node_t *L,unsigned int pos,data_t data);
//头插法
int head_insert(Node_t *L,data_t data){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
int i = 0;
Node_t *newnode = create_list(); //创建新的节点
newnode->data = data; //给新节点赋值
newnode->next = L->next; //让新节点指向头节点的下一个节点
L->next = newnode; //让头节点指向新节点
return 0;
}
//尾插法
int tail_insert(Node_t *L,data_t data){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
if (NULL == L->next)
{
head_insert(L,data);
return 0;
}
Node_t *newnode = create_list();
if(NULL != newnode->next){
puts("<<新节点创建失败>>");
return -1;
}
newnode->data = data; //给新节点赋值
newnode->next = NULL;
Node_t *temp = L->next; //使用临时指针变量保存链表
while (NULL != temp->next) //循环找到链表最后一个成员
{
temp = temp->next;
}
temp->next = newnode; //让最后一个成员指向新节点
return 0;
}
//任意位置插入
int pos_insert(Node_t *L,unsigned int pos,data_t data){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
//表空判断
if (NULL == L->next)
{
head_insert(L,data);
return 0;
}
Node_t *newnode = create_list(); //给新节点分配空间
newnode->data = data; //给新节点赋值
Node_t *temp = L; //创建临时变量保存链表
//插入位置合理性判断
for (int i = 0; i < pos-1; i++)
{
temp = temp->next;
if (NULL == temp)
{
puts("<<插入位置错误>>");
free(newnode); //如果插入位置不合理需要释放之前给新节点申请的空间
return -1;
}
}
//插入操作
newnode->next = temp->next;
temp->next = newnode;
return 0;
}
2.1.4链表成员的删除(构建函数)
//头部删除
int head_delet(Node_t *L);
//尾部删除
int tail_delet(Node_t *L);
//任意位置删除
int pos_dleet(Node_t *L,unsigned int pos);
//头部删除
int head_delet(Node_t *L){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
if (NULL == L->next)
{
puts("<<表为空 删除失败>>");
return -1;
}
Node_t *del = L->next;
L->next = del->next;
free(del);
del = NULL;
return 0;
}
//尾部删除
int tail_delet(Node_t *L){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
//表空判断
if (NULL == L->next)
{
puts("<<表为空 删除失败>>");
return -1;
}
//成员唯一判断
//如果不判断,当成员唯一时,链表尾的查找会越界
if (NULL == L->next->next)
{
head_delet(L);
return 0;
}
Node_t *temp = L;
while (NULL != temp->next->next) //注意越界
{
temp = temp->next;
}
Node_t *del = temp->next;
temp->next = NULL;
free(del);
return 0;
}
//任意位置删除
int pos_dleet(Node_t *L,unsigned int pos){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
//表空判断
if (NULL == L->next)
{
puts("<<表空,删除失败>>");
return -1;
}
//成员唯一判断
if (NULL == L->next->next)
{
head_delet(L);
return 0;
}
Node_t *delnode = create_list();
Node_t *temp = L;
//删除位置合理性判断
for (int i = 0; i < pos-1; i++)
{
temp = temp->next;
if (NULL == temp->next)
{
puts("<<删除位置错误>>");
free(delnode);
return -1;
}
}
delnode = temp->next;
temp->next = delnode->next;
free(delnode);
return 0;
}
2.1.5链表的排序(构建函数)
//链表排序
int sort_list(Node_t *L){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
//表空判断
if (NULL == L->next)
{
puts("<<表空,删除失败>>");
return -1;
}
//成员唯一判断
if (NULL == L->next->next)
{
head_delet(L);
return 0;
}
//通过创建两个指针 先后遍历链表进行数据比较
Node_t *first = L->next;
Node_t *second = first->next;
data_t temp = 0;
while (NULL != first->next) //冒泡排序的思想
{
while (NULL != second)
{
if (first->data <= second->data) //判断为真 交换数据
{
temp = first->data;
first->data = second->data;
second->data = temp;
}
second = second->next; //第二个指针向后走
}
first = first->next; //数据交换成功 两个指针同时向后走
second = first->next;
}
return 0;
}
2.1.6链表的翻转 (构建函数)
//链表的反转
int reversal_list(Node_t *L){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
//表空判断
if (NULL == L->next)
{
puts("<<表空,反转失败>>");
return -1;
}
//成员唯一判断
if (NULL == L->next->next)
{
puts("<<只有一个成员无需反转>>");
return 0;
}
//方法一
Node_t *new_L = L->next->next;
L->next->next = NULL;
Node_t *temp = new_L;
while (NULL != new_L)
{
temp = temp->next;
new_L->next = L->next;
L->next = new_L;
new_L = temp;
}
//方法二
// Node_t *temp = L->next;
// Node_t *new_L = L;
// new_L->next = NULL;
// while (NULL != temp)
// {
// head_insert(new_L,temp->data);
// temp = temp->next;
// }
return 0;
}
2.1.7链表的遍历及释放(构建函数)
//遍历链表
int show_list(Node_t *L);
//释放链表
int free_list(Node_t **L);
//遍历链表
int show_list(Node_t *L){
//健壮性判断
if (NULL == L)
{
puts("<<传参为空>>");
return -1;
}
Node_t *temp = L->next;
while (NULL!= temp)
{
printf("%d\n",temp->data);
temp = temp->next;
}
}
//释放链表
int free_list(Node_t **L){
//健壮性判断
if (NULL == L || NULL == *L)
{
puts("<<传参为空>>");
return -1;
}
//方法一
Node_t *temp = *L;
Node_t *fr_temp = NULL;
while (NULL != temp->next)
{
fr_temp = temp->next;
temp->next = fr_temp->next;
free(fr_temp);
fr_temp = NULL;
}
free(temp);
temp = NULL;
*L = NULL;
//方法二
// Node_t *temp = *L;
// while (NULL!=(*L))
// {
// temp = (*L)->next;
// printf("%d 节点将会被释放\n",(*L)->data);
// free(*L);
// *L = temp;
// }
return 0;
}