表: 顺序(数组) 、 链式(链表)
一、顺序表
- 数据项:
存储元素的内存首地址
表的容量
元素的数量
- 运算:
创建、销毁、清空、插入、删除、访问、查询、修改、排序、遍历
- 注意:
1、要确保数据元素的连续性
2、不能越界
- array 顺序表
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define TYPE int
#define PH "%d "
// 设计顺序表结构
typedef struct Array
{
TYPE* ptr; // 存储元素的内存首地址
size_t cal; // 表的容量
size_t cnt; // 元素的数量
}Array;
// 创建
Array* create_array(size_t cal)
{
// 给顺序表结构分配内存
Array* arr = malloc(sizeof(Array));
// 给数据元素分配内存
arr->ptr = malloc(sizeof(TYPE)*cal);
// 记录表的容量
arr->cal = cal;
// 初始化元素的数量
arr->cnt = 0;
return arr;
}
// 销毁
void destroy_array(Array* arr)
{
free(arr->ptr);
free(arr);
}
// 清空
void clear_array(Array* arr)
{
arr->cnt = 0;
}
// 插入
bool insert_array(Array* arr,size_t index,TYPE data)
{
// 判断表是否满
if(arr->cnt >= arr->cal) return false;
// 判断下标是否能保持元素的连续性
if(index > arr->cnt) return false;
/*
// 数据向后移动
for(int i=arr->cnt; i>index; i--)
{
arr->ptr[i] = arr->ptr[i-1];
}
*/
memmove(arr->ptr+index+1,arr->ptr+index,(arr->cnt-index)*sizeof(TYPE));
// 插入数据
arr->ptr[index] = data;
arr->cnt++;
return true;
}
// 删除
bool delete_array(Array* arr,size_t index)
{
if(index >= arr->cnt) return false;
/*
for(int i=index; i<arr->cnt-1; i++)
{
arr->ptr[i] = arr->ptr[i+1];
}
*/
memmove(arr->ptr+index,arr->ptr+index+1,(arr->cnt-index-1)*sizeof(TYPE));
arr->cnt--;
return true;
}
// 访问
bool access_array(Array* arr,size_t index,TYPE* data)
{
if(index >= arr->cnt) return false;
*data = arr->ptr[index];
return true;
}
// 查询
int query_array(Array* arr,TYPE data)
{
for(int i=0; i<arr->cnt; i++)
if(arr->ptr[i] == data) return i;
return -1;
}
// 修改
bool modify_array(Array* arr,size_t index,TYPE data)
{
if(index >= arr->cnt) return false;
arr->ptr[index] = data;
return true;
}
// 排序
void sort_array(Array* arr)
{
for(int i=0; i<arr->cnt-1; i++)
{
for(int j=i+1; j<arr->cnt; j++)
{
if(arr->ptr[j] < arr->ptr[i])
{
TYPE temp = arr->ptr[j];
arr->ptr[j] = arr->ptr[i];
arr->ptr[i] = temp;
}
}
}
}
// 遍历
void show_array(Array* arr)
{
for(int i=0; i<arr->cnt; i++)
{
printf(PH,arr->ptr[i]);
}
printf("\n");
}
int main(int argc,const char* argv[])
{
Array* arr = create_array(10);
for(int i=0; i<5; i++)
{
insert_array(arr,0,i+1);
}
insert_array(arr,1,8);
delete_array(arr,5);
show_array(arr);
int num = 0;
if(access_array(arr,5,&num))
printf("num=%d\n",num);
else
printf("index error\n");
printf("index=%d\n",query_array(arr,80));
sort_array(arr);
clear_array(arr);
show_array(arr);
destroy_array(arr);
}
二、链式表list
- 数据元素(节点)的数据项:
数据域:可以是各种类型的若干项数据项
指针域:指向下一个节点的指针
由若干个节点通过指针域连接起来就形成了链表
- list 链表
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
// 设计链表的节点结构
typedef struct Node
{
TYPE data; // 节点的数据域
struct Node* next; // 节点的指针域
}Node;
// 创建节点
Node* create_node(TYPE data)
{
// 申请节点的内存
Node* node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
// 头添加
void add_head_list(Node** head,TYPE data)
{
// 创建待添加的节点
Node* node = create_node(data);
node->next = *head; //带头节点node->next = head->next;
*head = node; //带头节点head->next = node;
}
// 按值删除
bool del_value_list(Node** head,TYPE data)
{
if((*head)->data == data)
{
Node* temp = *head;
*head = (*head)->next;
free(temp);
return true;
}
// 遍历找到待删除节点的前一个节点
for(Node* n=*head; n->next; n=n->next)
{
if(n->next->data == data)
{
Node* temp = n->next;
n->next = n->next->next;
free(temp);
return true;
}
}
return false;
}
// 遍历链表
void show_list(Node* head)
{
for(Node* n=head; n; n=n->next)
//带头节点for(Node* n=head->next; n; n=n->next)
{
printf("%d ",n->data);
}
printf("\n");
}
// 访问
bool access_list(Node* head,size_t index,TYPE* data)
{
int i = 0;
for(Node* n = head; n; n=n->next,i++)
{
if(i == index)
{
*data = n->data;
return true;
}
}
return false;
}
// 排序
void sort_list(Node* head)
{
for(Node* i=head; i->next; i=i->next)
{
for(Node* j=i->next; j; j=j->next)
{
if(j->data < i->data)
{
TYPE temp = j->data;
j->data = i->data;
i->data = temp;
}
}
}
}
// 按位置删除
bool del_index_list(Node** head,size_t index)
{
if(0 == index)
{
Node* temp = *head;
*head = temp->next;
free(temp);
return true;
}
Node* n = *head;
for(int i=1; n->next; n=n->next,i++)
{
if(i == index)
{
Node* temp = n->next;
n->next = temp->next;
free(temp);
return true;
}
}
return false;
/*
while(--index)
{
n = n->next;
if(NULL == n) return false;
}
if(NULL == n->next) return false;
Node* temp = n->next;
n->next = temp->next;
free(temp);
*/
return true;
}
int main(int argc,const char* argv[])
{
Node* head = create_node(10);
for(int i=0; i<5; i++)
{
add_head_list(&head,i+1);
}
show_list(head);
del_value_list(&head,100);
show_list(head);
int num = 0;
access_list(head,20,&num);
printf("num=%d\n",num);
sort_list(head);
show_list(head);
del_index_list(&head,2);
show_list(head);
/* 理解链表的本质
Node* n1 = create_node(10);
Node* n2 = create_node(20);
Node* n3 = create_node(30);
Node* n4 = create_node(40);
n1->next = n2;
n2->next = n3;
n3->next = n4;
for(Node* n=n1; n; n = n->next)
{
printf("%d ",n->data);
}
*/
}
2.1不带头节点的链表:
定义:第一个节点的数据域存储的是有效数据
缺点:当插入、删除时可能会改变第一个有效节点,传递的参数需要传递二级指针,实现时需要区分是否是操作第一个有效节点,较为麻烦
2.2带头节点的链表:
定义:第一个节点作为头节点,数据域不使用不存储有效数据,它的指针域永远指向链表的第一个有效数据节点,就算链表长度为0,头节点依然存在
有效数据节点的处理应当从head->next开始
- 链表list
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
typedef struct Node
{
TYPE data;
struct Node* next;
}Node;
// 创建节点
Node* create_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
// 头添加
void add_head_list(Node* head,TYPE data)
{
Node* node = create_node(data);
node->next = head->next;
head->next = node;
}
// 遍历
void show_list(Node* head)
{
// 有效数据节点的处理应当从head->next开始
for(Node* n=head->next; n; n=n->next)
{
printf("%d ",n->data);
}
printf("\n");
}
// 尾添加
void add_tail_list(Node* head,TYPE data)
{
Node* node = create_node(data);
Node* n = head;
while(n->next) n = n->next;
n->next = node;
}
// 插入
bool insert_list(Node* head,size_t index,TYPE data)
{
Node* n = head;
for(int i=0; n->next; n=n->next,i++)
{
if(i == index)
{
Node* node = create_node(data);
node->next = n->next;
n->next = node;
return true;
}
}
return false;
}
// 按位置删除
bool del_index_list(Node* head,size_t index)
{
Node* n = head;
for(int i=0; n->next; n=n->next,i++)
{
if(i == index)
{
Node* temp = n->next;
n->next = temp->next;
free(temp);
return true;
}
}
return false;
}
// 按值删除
int del_value_list(Node* head,TYPE data)
{
int cnt = 0;
Node* n = head;
while(n->next)
{
if(data == n->next->data)
{
Node* temp = n->next;
n->next = temp->next;
free(temp);
cnt++;
}
else
n = n->next;
}
return cnt;
}
// 修改
bool modify_list(Node* head,TYPE old,TYPE data)
{
}
// 访问
bool access_list(Node* head,size_t index,TYPE* data)
{
}
// 排序
void sort_list(Node* head)
{
}
int main(int argc,const char* argv[])
{
// head 指向头节点 不使用为有效数据节点
// head->next指向第一个有效数据节点
Node* head = create_node(100);
for(int i=0; i<10; i++)
{
add_tail_list(head,i+1);
}
show_list(head);
insert_list(head,3,88);
insert_list(head,5,88);
insert_list(head,8,88);
insert_list(head,3,88);
show_list(head);
printf("%d\n",del_value_list(head,88));
show_list(head);
del_index_list(head,20);
show_list(head);
}
优点:当插入、删除时是不会改变头节点的指向,只需要改变它的next,因此无需传递头节点的二级指针,并且实现时无需区分两种情况
注意:有效节点的处理必须从头节点的next开始
注意:笔试题时,如果题目没有说明链表是否带头节点,应该两种情况都进行分析
标签:Node,index,arr,head,next,数据结构,data From: https://www.cnblogs.com/ljf-0804/p/17686570.html