目录
Part1.线性表
Part2.顺序表(本质上就是数组,但是在数组的基础上,它还要求数据是连续存储的)
Part3.单链表
?单链表的操作(增删查改):
Part1.线性表
????????线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...等。 ????????线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
Part2.顺序表(本质上就是数组,但是在数组的基础上,它还要求数据是连续存储的)
????????顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。 ????????顺序表一般可以分为: ????????????????1. 静态顺序表:使用定长数组存储。 ????????????????2. 动态顺序表:使用动态开辟的数组存储。
// 顺序表的静态存储
#define N 100
typedef int SLDataType;
typedef struct SeqList
{
SLDataType array[N]; // 定长数组
size_t size; // 有效数据的个数
}SeqList;
// 顺序表的动态存储
typedef struct SeqList
{
SLDataType* array; // 指向动态开辟的数组
size_t size ; // 有效数据个数
size_t capicity ; // 容量空间的大小
}SeqList;
Part3.单链表
链表的内存是不连续的,元素会各自被分配一块内存,内存与内存之间用指针进行连接。
单链表一般分为数据域和指针域,数据域用于存放数据,指针域存放下一个节点的地址。
链表是由n个节点连接成的,第一个节点的存储位置叫做头指针,最后一个节点的指针为空
?单链表的操作(增删查改):
1、创建节点结构体
#include <stdio.h>
#include <stdlib.h>
//定义数据结构
typedef struct Node
{
int data; //数据域
struct Node* next; //指针域 (保存下一个节点的地址)
}Node;
2、初始化链表(空链表,初始化后只有头节点,返回值是头节点)
头节点:在单链表中的第一个节点前附设的一个节点,指向链表中的第一个元素
//初始化链表
//在定义链表时,习惯性的会定义头节点,以便统一链表节点的插入和删除
Node* initList()
{
Node* list = (Node*)malloc(sizeof(Node)); //开辟头节点空间
list -> data =0; //记录链表内的节点个数
list -> next =NULL; //因为现在只有头节点,所以下一个是空
return list; //返回头节点
}
3、增加
头插法:插到最顶部,取代之前的首节点
//头插法插入节点
void headInsert(Node* list, int data) //传入头节点和新节点的数据
{
Node* node = (Node*)malloc(sizeof(Node)); //开辟插入的新节点的空间
node -> data = data; //给新节点赋值
node -> next = list -> next; //因为当前链表未插入前只有头节点,所以新节点插入到头节点的下一
//个节点
list -> next = node; //头节点的下一个节点是新节点,头节点保存新节点node的地址
list -> data++; //list的数据域保存的是链表元素的个数,插入一个节点链表的节点数+1
}
尾插法:插到最尾部,让链表中之前的最后一个节点指向这个要插入的新节点,这个新节点指向NULL
//尾插法
void tailInsert(Node* list, int data) //传入头节点和新节点的数据
{
Node*current=list; //把头节点传给这个当前节点,现在这个节点就和头节点一样,用来轮询查找尾节点
Node* node = (Node*)malloc(sizeof(Node)); //为新节点开辟空间
node -> data = data;
node -> next = NULL;
current = list -> next; //当前节点指向头节点下一个元素,也就是第一个元素
while(current -> next != NULL ) //如果current下一个节点非空 继续查找
{
current = current -> next; //递增
}
//循环结束表示找到了最后一个节点
current -> next = node; //把node插到最后一个节点后面,最后一个节点保存新插入节点的地址
list -> next++; //链表节点个数+1
}
4、删除(只需要找到要删除的对应节点,将对应节点的前一个节点保存的地址指向对应节点的后继节点的地址,然后free释放要删除的节点)
//删除节点
void delete(Node* list, int data) //传入头节点和要删除节点的数据
{
Node* current = list; //定义当前节点(一开始在头节点位置)
Node* pre = list; //定义要删除节点的前一个节点
current = list -> next; //当前节点指向第一个元素
while (current -> next != NULL ) //循环查找
{
if (current -> data == data) //如果当前节点的值等于要删除节点的值,也就是找到了
{
pre -> next = current -> next; //让当前节点的前一个节点的保存的地址跟当前节点的下
//一个节点的地址相连接
free(current); //释放删除的节点
break;
}
current = current ->next; //如果没找到继续查找
}
list -> data--; //链表节点-1
}
5.查找? (查询指定值)
//查询指定的节点 (一个个找)
Node* findNode(Node* list, int data)
{
Node* current = list;
current = list -> next; //指向第一个节点
while(current -> next != NULL)
{
if (current -> data == data) //当前值就是要查找的值,也就是找到了
{
return current; //返回要查找的节点
}
current = current -> next;
}
return -1; //返回-1表示没找到
}
6、查找 (遍历链表)
//遍历
void printList(Node* list) //传入头节点
{
Node* current = list;
current = list -> next;
while(current -> next != NULL)
{
printf("%d\n",current -> data); //打印当前节点的值
current = current -> next; //指向下一个
}
}
7、主函数测试
int main()
{
Node* list = initList();
//头插
headInsert(list, 1);
headInsert(list, 2);
headInsert(list, 3);
headInsert(list, 4);
headInsert(list, 5);
//尾插
tailInsert(list, 6);
tailInsert(list, 6);
tailInsert(list, 7);
tailInsert(list, 8);
tailInsert(list, 9);
tailInsert(list, 10);
//遍历
printList(list);
//删除
delete(list, 6);
return 0;
}
Part4.栈
????????栈(stack)是限定仅在表尾进行插入或者删除的线性表。对于栈来说,表尾端称为栈顶(top),表头端称为栈低(bottom)。不含元素的空表称为空栈。因为栈限定在表尾进行插入或者删除,所以栈又被称为后进先出 的线性表(简称LIFO:Last in, First out. 结构)。
栈的基本操作:
1、定义节点
#include <stdio.h>
#include <stdlib.h>
//定义数据结构
typedef struct Node
{
int data; //数据域
struct Node* next; //指针域 (保存下一个节点的地址)
}Node;
?2、初始化链表(空链表,初始化后只有头节点,返回值是头节点)
//初始化链表
//在定义链表时,习惯性的会定义头节点,以便统一链表节点的插入和删除
Node* initList()
{
Node* L = (Node*)malloc(sizeof(Node)); //开辟头节点空间
L -> data =0; //记录链表内的节点个数
L -> next =NULL; //因为现在只有头节点,所以下一个是空
return L; //返回头节点
}
3、出栈、入栈
//首先判断栈时候为空
int isEmpty(Node* L)
{
if(L -> data == 0 || L -> next == NULL) //空栈返回1
{
return 1;
}
else
{
return 0;
}
}
//获取栈的元素
int getpop(Node* L)
{
if(isEmpty(L))
{
return -1;
}
else
{
Node* node = L -> next;
int data = node -> data;
L -> next = node -> next;
free(node);
return data;
}
}
//入栈
void push(Node* L, int data)
{
Node* node = (Node*)malloc(sizeof(Node)); //入栈的新节点
node -> data = data;
node -> next = L -> next; //头节点指向新节点
L -> next = node;
L -> date++; //节点数+1
}
//遍历栈
void printStack(Node* L)
{
Node* node = L -> next;
while(node != NULL)
{
printf("%d -> ", node -> data);
node = node -> next;
}
printf("NULL\n");
}
|