这周开始我就开始学习数据结构了,数据结构好难啊,显示讲什么是数据结构,然后讲 时间复杂度,顺序表,链表,顺序栈,链栈,顺序循环队列,链式队列,暂时只讲了这么多,后面还有树跟哈希表下周再上,等我上完过后再来讲这两个,下面我i将仔细地讲讲我这周上过的。
为什么学习数据结构:为了提高程序的运行效率
什么是数据:是对事物进行的记录并可以鉴别的符号,对我们有用的信息都可以成为数据。
什么是结构:指元素(数据)的相互关联和相互作用的关系。
根据数据元素之间的关系,分成4个基本结构:
-
集合:结构中的数据是在同属空间内,没有其它关系,比如刚入学的学生。
-
线性结构:数据为一一对应的关系,比如已分发学号的学生shijianfuzhadu ,图书馆的图书。
-
树状结构(层次关系):数据为一对多的关系,家族的族谱,公司的架构。
-
图状结构(网状结构):数据为多对多的关系,城市与城市之间的交通干线。
算法:算法分析是指在正常程序工作之下,对齐优略分析。
时间复杂度:描述程序运行的时间复杂度BigO即大O表示法,计算的是程序运行的次数而不是程序运行的时间,时间复杂度 = 程序运行的次数。
公式: T(n) = O(f(n))
T(n) : 表示算法的渐进时间复杂度
f(n) : 程序运行的次数
O : 表示正比关系
常用的时间复杂度:
1.常数阶O(1)
int a = 1;
int b = a;
2.对数阶O(logN)==》2^k = N ==> K = logN,k为程序运行的次数
int i = 1;
while(i < n)
i = 2*i;
3.线性阶O(N)
for(int i = 1; i <= n; i++)
x++
4.线性对数阶O(NlogN)
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <=n; j+=i)
{
x++;
}
}
5.平方阶(n^2)
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
x++;
}
![]()
一个小练习
计算过下列的时间复杂度:
1.
for(int i = 1; i <= n; i=i*2)
{
printf("%d\t",i);
}
2^i = n ===>i = logN
2.
int i = 0;
int s = 0;
while(s < n)
{
++i;
s+=i;
}
1+2+3+...+k = k(k+1)/2==>k^2+k=2n==>因为k和2是常量,忽略==>k^2=n==>k=根号n
线性表
概念:一对一的数据所组成的关系称为线性表,注意线性是逻辑结构.
特点:
(1) 存在唯一的一个被称为"第一个"的数据元素。
(2) 存在唯一的一个被称为"最后一个"的数据元素。
(3) 除了第一个外,集合中每一个数据元素只有一个前驱节点。
(4) 除了最后一个外,集合中每个数据元素均只有一个后驱节点。
注意:
1.线性表是一种数据内部的逻辑关系,与存储形式无关。
2.线性表既可以采用连续的顺序存储(数组),也可以采用离散的链式存储(链表)。
3.顺序表和链表都称为线性表。
顺序表
概念:顺序存储的线性表。
基本操作:我用代码来表示
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct sequenList
{
int cap; // 顺序表总大小
int last; // 顺序表元素下标
int *data; // 指向顺序表的首元素地址
}sequenList;
//初始化表
sequenList *init_seque(int cap)
{
if(cap <= 0)
return NULL;
//给顺序管理结构体分配空间
sequenList *head = malloc(sizeof(sequenList));
if(head == NULL)
return NULL;
head->cap = cap;
head->last = -1;
head->data = calloc(cap,sizeof(int));
if(head->data == NULL)
return NULL;
return head;
}
//判断表是否满
bool isFull(sequenList *head)
{
if(head->cap == head->last + 1)
return true;
return false;
}
//插入数据
bool insert(sequenList *head, int data)
{
if(head == NULL)
return false;
//判断数据是否已满
if(isFull(head))
return false;
head->data[++head->last] = data;
return true;
}
//判断表为空
bool isEmpty(sequenList *head)
{
if(head->last == -1)
return true;
return false;
}
//显示插入数据
void showList(sequenList *head)
{
if(isEmpty(head))
return;
for(int i = 0; i < head->last+1; i++)
{
printf("%d\t", head->data[i]);
}
printf("\n");
}
//删除数据
bool removeData(sequenList *head, int data)
{
if(isEmpty(head))
return false;
//寻找要删除的内容
int i = 0;
while(i <= head->last)
{
if(head->data[i] == data)
{
//找到需要的数据,使其后面的数据覆盖他
for(int j = i; j < head->last ;j++)
{
head->data[j] = head->data[j + 1];
}
i = -1;
head->last--;
}
i++;
//printf("data = %d\t\n", head->data[i]);
}
if(i == head->last)
return true;
return true;
}
//销毁顺序表
void destroy(sequenList *head)
{
if(head == NULL)
return;
free(head->data);
free(head);
}
//排序
void bubble(sequenList *head)
{
for(int i = 0; i < head->last; i++)
{
for(int j = 0; j < head->last - i; j++)
{
if(head->data[j] > head->data[j + 1])
{
int temp = head->data[j];
head->data[j] = head->data[j + 1];
head->data[j + 1] = temp;
}
}
}
}
int main(int argc, char const *argv[])
{
int count = 0;
//初始化表
sequenList *head = init_seque(10);
if(head == NULL)
{
printf("init failed\n");
return -1;
}
printf("请输入数据\n");
for(int i = 0; i < 7; i++)
{
int data;
scanf("%d", &data);
//将输入插入到表
insert(head,data);
}
bubble(head);
for(int i = 0; i < head->last; i++)
{
if( head->data[i] < 0)
{
//head->data[i] = ~(head->data[i] -1);
removeData(head,-head->data[i]);
removeData(head,head->data[i]);
i--;
}
}
//显示
showList(head);
destroy(head);
return 0;
}
顺序表的优缺点
优点:
不需要多余的信息来记录数据的关系,存储密度高。
所有数据顺序存储在一片连续的内存中,支持立即访问任意一个随机数 据,比如上述顺序表中第i个节点是s->data。
缺点:
插入、删除时需要保持数据的物理位置反映其逻辑关系,需要成片移动数据。
当数据节点较多时,需要一整片较大的连续内存空间。
当数据节点数量变化剧烈时,内存的释放和分配不灵活。
链式表与顺序表类似,但也有差异:
既然顺序存储中的数据因为挤在一起而导致需要成片移动,那很容易想到的解决方案是将数据离散地存储在不同内存块中,然后在用来指针将它们串起来。这种朴素的思路所形成的链式线性表,就是所谓的链表。
链表的分类:单向链表与双向链表,循环链表,有头结点的单向链表与无头结点的单向链表。
下面我将用代码来展示这些不同的链表
无头结点的单向链表;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef int dataType;
// 节点
struct node
{
dataType data;// 指针域
struct node *next; // 指向下一个节点
};
// 创建新节点
struct node *create_newNode(dataType data)
{
struct node *pnew = malloc(sizeof(struct node));
if(pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
// 创建链表
struct node *create_list(void)
{
// 设置空链表
struct node *head = NULL;
struct node *tail = NULL;
while(1)
{
dataType data;
if(scanf("%d",&data) == 0)
break;
// 创建新节点
struct node *pnew = create_newNode(data);
if(pnew == NULL)
{
printf("create new node failed:\n");
//exit(0); // 不管再哪里调用,整个程序结束
return NULL; // 只退出本函数
}
// 从无到有
if(head == NULL)
{
head = pnew;
tail = pnew;
}
else// 从少到多
{
// 尾插法
//tail->next = pnew;
//tail = pnew;
// 头插法
pnew->next = head;
head = pnew;
}
}
return head;
}
//增加节点
struct node *insertNode(struct node** head, int position, int data)
{
// 创建新节点
struct node* newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = data;
newNode->next = NULL;
// 如果要插入的位置是链表的头部
if (position == 0)
{
newNode->next = *head;
*head = newNode;
return 0;
}
// 找到要插入位置的前一个节点
struct node *current = *head;
for (int i = 0; i < position - 1 && current != NULL; i++)
{
current = current->next;
}
// 如果找到了要插入位置的前一个节点
if (current != NULL)
{
newNode->next = current->next;
current->next = newNode;
}
else
{
printf("Invalid position\n");
}
}
// 显示链表
void show_list(struct node *head)
{
if(head == NULL)
return;
for(struct node *p = head; p != NULL; p = p->next)
{
printf("%d\t",p->data);
}
printf("\n");
}
//修改节点
void revise_node(struct node *head, dataType data)
{
while(1)
{
if(head->data != data && head->next != NULL)
{
head = head->next;
}
else if(head->data == data)
{
head->data = 3;
break;
}
else
{
break;
}
}
}
//删除节点
struct node *removed(struct node *head, int data)
{
struct node *p = head;
if(head->data == data)
{
head = head->next;
}
while(p->next != NULL)
{
if(p->next->data == data)
{
p->next = p->next->next;
}
p = p->next;
}
return head;
}
int main(int argc, char const *argv[])
{
// 创建链表
struct node *head = create_list();
if(head == NULL)
return -1;
//修改节点
//revise_node(head, 8);
//删除节点
head = removed(head, 5);
//增加节点
//insertNode(&head,3,5);
// 显示链表
show_list(head);
return 0;
}
有头结点的单向链表
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef int dataType;
//数据节点
struct node
{
dataType data;
struct node *next;
};
//头节点,管理结构体
struct headNode
{
struct node *first; //指向头节点
struct node *tail; //指向尾节点
int nodeNumber; //链表节点个数
};
struct headNode *init_headNode(void)
{
struct headNode *head = malloc(sizeof(struct headNode));
if(head == NULL)
return NULL;
head->first = NULL;
head->tail = NULL;
head->nodeNumber = 0;
return head;
}
//创建新节点
struct node *creat_newNode(dataType data)
{
struct node *pnew = malloc(sizeof(struct node));
if(pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
//创建带头节点的单向链表
struct headNode *creat_list(void)
{
//初始化管理结构体
struct headNode *head = init_headNode();
if(head == NULL)
return NULL;
while(1)
{
dataType data;
if(scanf("%d", &data) == 0)//退出
break;
//创建新节点
struct node *pnew = creat_newNode(data);
//从无到有
if(head->first == NULL)
{
head->first = pnew;
head->tail = pnew;
}
else //从少到多
{
//头插法
//pnew->next = head->first;
//head->first = pnew;
//尾插法
head->tail->next = pnew;
head->tail = pnew;
}
//新增节点
head->nodeNumber++;
}
return head;
}
//更新节点
struct headNode *updata_node(struct headNode *head,dataType newData,dataType data)
{
//找节点
struct node *p = head->first;
while(p)
{
if(p->data == data)
{
p->data = newData;
break;
}
else//继续找
{
p = p->next;
}
}
if(p == NULL)
{
printf("没有需要替换的数据\n");
}
return head;
}
//添加节点
struct headNode *add_node(struct headNode *head,dataType newData,dataType data)
{
//创建新节点
struct node *pnew = creat_newNode(newData);
if(pnew == NULL)
return NULL;
//找位置
struct node *p = head->first; //遍历指针
struct node *pre = NULL; //p的前驱指针
while(p)
{
if(p->data == data)
{
break;
}
else
{
pre = p;
p = p->next;
}
}
//找不到,尾插
if(p == NULL)
{
head->tail->next = pnew;
head->tail = pnew;
}
else if(head->first->data == p->data)//头插
{
pnew->next = head->first;
head->first = pnew;
}
else//中间
{
pnew->next = p;
pre->next = pnew;
}
//更新节点数
head->nodeNumber++;
return head;
}
//删除节点
struct headNode *remove_node(struct headNode *head,dataType data)
{
//找节点
struct node *p = head->first; //遍历指针
struct node *pre = NULL;
while(p)
{
if(p->data == data)
{
break;
}
else
{
pre = p;
p = p->next;
}
}
if(p == NULL)//找不到
{
printf("没有需要删除的节点\n");
return head;
}
if(p == head->first)//首节点
{
head->first = p->next;
p->next = NULL;
free(p);
}
else if(p == head->tail)//尾节点
{
head->tail = pre->next;
pre->next = NULL;
free(p);
}
else//中间
{
pre->next = p->next;
p->next = NULL;
free(p);
}
//更新链表个数
head->nodeNumber--;
return head;
}
//判断链表是否为空
bool isEmpty(struct headNode *head)
{
if(head->nodeNumber == 0)
return true;
return false;
}
//销毁链表
void destroy_list(struct headNode *head)
{
if(isEmpty(head))
{
return ;
}
struct node *tmp = NULL;
for(struct node *p = head->first; p != NULL; p = tmp)
{
tmp = p->next;
p->next = NULL;
free(p);
head->nodeNumber--;
}
}
//链表逆序
struct headNode *reverse_list(struct headNode *head)
{
//指向首节点
struct node *p = head->first;
//指向拆下来的节点
struct node *pnew = NULL;
//拆头节点
head->first = NULL;
head->tail = NULL;
//头插法插入拆下来的节点
while(p)
{
pnew = p;
p = p->next;
//断开pnew
pnew->next = NULL;
if(head->first = NULL)
{
head->first = pnew;
head->tail = pnew;
}
else
{
//头插法
pnew->next = head->first;
head->first = pnew;
}
}
}
//显示链表
void show_list(struct headNode *head)
{
if(isEmpty(head))
return;
for(struct node *p = head->first; p != NULL; p = p->next)
{
printf("%d\t", p->data);
}
printf("\n");
printf("链表已有%d个节点", head->nodeNumber);
}
int main(int argc, char const *argv[])
{
//创建链表
struct headNode *head = creat_list();
if(head == NULL)
return -1;
//更新节点
//head = updata_node(head,8,8);
//添加节点
//head = add_node(head,3,3);
//删除节点
//head = remove_node(head,3);
//显示
show_list(head);
//销毁链表
destroy_list(head);
return 0;
}
双向链表
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef int dataType;
//节点
struct node
{
dataType data;
struct node *per;//指向上一个节点
struct node *next;//指向下一个节点
};
//创建头节点,管理结构体
struct headNode
{
struct node *first;//指向头节点
struct node *tail;//指向尾节点
dataType nodeNumbre;//记录节点数
};
//初始化管理结构体
struct headNode *init_headNode()
{
struct headNode *head = malloc(sizeof(struct headNode));
if(head == NULL)
return NULL;
head->first = NULL;
head->tail = NULL;
head->nodeNumbre = 0;
}
//创建新节点
struct node *creat_newNode(dataType data)
{
struct node *pnew = malloc(sizeof(struct node));
if(pnew == NULL)
return NULL;
pnew->next = NULL;
pnew->per = NULL;
pnew->data = data;
return pnew;
}
//尾插法
struct headNode *addTail()
{
}
//创建链表
struct headNode *creat_list(void)
{
//初始化管理结构体
struct headNode *head = init_headNode();
if(head == NULL)
return NULL;
while(1)
{
dataType data;
if(scanf("%d", &data) == 0)
break;
//创建新节点
struct node *pnew = creat_newNode(data);
if(head->first == NULL)//从无到有
{
head->first = pnew;
head->tail = pnew;
}
else//从少到多
{
//头插法
pnew->next = head->first;
pnew->per = head->first->per;
head->first->per = pnew;
head->first = pnew;
//尾插法
//pnew->per = head->tail;
//head->tail->next = pnew;
//head->tail = pnew;
}
head->nodeNumbre++;
}
return head;
}
//修改节点
struct headNode *updata_Node(struct headNode *head, dataType data, dataType newData)
{
struct node *p = head->first;
while(p)
{
if(p->data == data)
{
p->data = newData;
break;
}
else
{
p = p->next;
}
}
if(p == NULL)
{
printf("没有找到\n");
}
return head;
}
//增加节点
struct headNode *addNode(struct headNode *head, dataType data, dataType newData)
{
struct node *pnew = creat_newNode(newData);
struct node *p = head->first;
if(pnew == NULL)
return NULL;
while(p)
{
if(p->data == data)
{
break;
}
else
{
p = p->next;
}
}
if(p == head->first)
{
pnew->next = head->first;
pnew->per = head->first->per;
head->first->per = pnew;
head->first = pnew;
}
if(p == NULL)
{
pnew->per = head->tail;
head->tail->next = pnew;
head->tail = pnew;
}
else
{
pnew->next = p;
pnew->per = p->per;
p->per->next = pnew;
p->per = pnew;
}
head->nodeNumbre++;
return head;
}
//删除节点
struct headNode *removeNode(struct headNode *head, dataType data)
{
struct node *p = head->first;
while(p)
{
if(p->data == data)
{
break;
}
else
{
p = p->next;
}
}
if(p == NULL)
{
printf("没有要删除的节点\n");
return head;
}
if(p == head->first)
{
head->first = p->next;
p->next->per = head->first;
p->next = NULL;
p->per = NULL;
free(p);
}
else if(p == head->tail)
{
head->tail = p->per;
p->per->next = NULL;
p->next = NULL;
free(p);
}
else
{
p->next->per = p->per;
p->per->next = p->next;
p->per = NULL;
p->next = NULL;
free(p);
}
head->nodeNumbre--;
return head;
}
bool isEmpty(struct headNode *head)
{
if(head == NULL)
return true;
return false;
}
//显示链表
void show_list(struct headNode *head)
{
if(isEmpty(head))
return;
for(struct node *p = head->first; p != NULL; p = p->next)
{
printf("%d\t", p->data);
}
printf("\n");
printf("链表有%d个节点\n", head->nodeNumbre);
}
int main(int argc, char const *argv[])
{
//创建链表
struct headNode *head = creat_list();
if(head == NULL)
return -1;
//修改节点
//head = updata_Node(head,3,5);
//删除节点
head = removeNode(head,3);
//增加节点
//head = addNode(head,3,4);
//显示链表
show_list(head);
return 0;
}
双向循环链表
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef int dataType;
//节点
struct node
{
dataType data;
struct node *per;//指向上一个节点
struct node *next;//指向下一个节点
};
//创建头节点,管理结构体
struct headNode
{
struct node *first;//指向头节点
struct node *tail;//指向尾节点
dataType nodeNumbre;//记录节点数
};
//初始化管理结构体
struct headNode *init_headNode()
{
struct headNode *head = malloc(sizeof(struct headNode));
if(head == NULL)
return NULL;
head->first = NULL;
head->tail = NULL;
head->nodeNumbre = 0;
return head;
}
//创建新节点
struct node *creat_newNode(dataType data)
{
struct node *pnew = malloc(sizeof(struct node));
if(pnew == NULL)
return NULL;
pnew->next = NULL;
pnew->per = NULL;
pnew->data = data;
return pnew;
}
//尾插法
struct headNode *addTail()
{
}
//创建链表
struct headNode *creat_list(void)
{
//初始化管理结构体
struct headNode *head = init_headNode();
if(head == NULL)
return NULL;
while(1)
{
dataType data;
if(scanf("%d", &data) == 0)
{
while(getchar() != '\n');
break;
}
//创建新节点
struct node *pnew = creat_newNode(data);
if(head->first == NULL)//从无到有
{
head->first = pnew;
head->tail = pnew;
}
else//从少到多
{
//头插法
//pnew->next = head->first;
//pnew->per = head->first->per;
//head->first->per = pnew;
//head->first = pnew;
//尾插法
pnew->per = head->tail;
head->tail->next = pnew;
head->tail = pnew;
}
head->nodeNumbre++;
}
//循环链表
if(head->nodeNumbre != 0)
{
head->tail->next = head->first;
head->first->per = head->tail;
}
return head;
}
//修改节点
struct headNode *updata_Node(struct headNode *head, dataType data, dataType newData)
{
struct node *p = head->first;
int n = head->nodeNumbre;
while(n)
{
if(p->data == data)
{
p->data = newData;
break;
}
else
{
p = p->next;
}
n--;
}
if(n == 0)
{
printf("没有找到\n");
}
return head;
}
//增加节点
struct headNode *addNode(struct headNode *head, dataType data, dataType newData)
{
struct node *pnew = creat_newNode(newData);
struct node *p = head->first;
if(pnew == NULL)
return NULL;
int n = head->nodeNumbre;
while(n)
{
if(p->data == data)
{
break;
}
else
{
p = p->next;
}
n--;
}
if(n == (head->nodeNumbre))//首节点
{
printf("_%d_\n", __LINE__);
pnew->next = head->first;
pnew->per = head->first->per;
head->first->per = pnew;
head->first = pnew;
}
else if(n == 0)//尾节点
{
printf("_%d_\n", __LINE__);
pnew->per = head->tail;
head->tail->next = pnew;
head->tail = pnew;
}
else//中间插
{
printf("_%d_\n", __LINE__);
pnew->next = p;
pnew->per = p->per;
p->per->next = pnew;
p->per = pnew;
}
head->nodeNumbre++;
//循环
if(head->nodeNumbre != 0)
{
head->tail->next = head->first;
head->first->per = head->tail;
}
return head;
}
//删除节点
struct headNode *removeNode(struct headNode *head, dataType data)
{
struct node *p = head->first;
int n = head->nodeNumbre;
while(n)
{
if(p->data == data)
{
break;
}
else
{
p = p->next;
}
n--;
}
if(n == 0)//找不到
{
printf("没有要删除的节点\n");
return head;
}
if(n == (head->nodeNumbre))//首节点
{
printf("_%d_\n", __LINE__);
head->first = p->next;
p->next->per = head->tail;
p->next = NULL;
p->per = NULL;
free(p);
}
else if(n == 1)//尾节点
{
head->tail = p->per;
p->per->next = NULL;
p->next = NULL;
free(p);
}
else //中间节点
{
p->next->per = p->per;
p->per->next = p->next;
p->per = NULL;
p->next = NULL;
free(p);
}
head->nodeNumbre--;
//循环
if(head->nodeNumbre != 0)
{
head->tail->next = head->first;
head->first->per = head->tail;
}
return head;
}
//判断链表是否有环
bool circulate(struct headNode *head)
{
if(head->first == NULL)
{
return false;
}
struct node *p = head->first;//快指针
struct node *ptr = head->first;//慢指针
do
{
p = p->next;
if(p != NULL)
{
p = p->next;
}
else
{
return false;
}
ptr = ptr->next;
}while(p != NULL && ptr != NULL && p != ptr);
//最终地址是否相等
return p == ptr;
while(p != NULL && ptr != NULL)
{
}
}
bool isEmpty(struct headNode *head)
{
if(head->nodeNumbre == 0)
return true;
return false;
}
//销毁链表
void destroy_list(struct headNode *head)
{
if(isEmpty(head))
{
return ;
}
struct node *tmp = NULL;
struct node *p = head->first;
int n = head->nodeNumbre;
while(n--)
{
tmp = p->next;
p->next = NULL;
free(p);
p = tmp;
head->nodeNumbre--;
}
}
//显示链表
void show_list(struct headNode *head)
{
if(isEmpty(head))
{
printf("链表已销毁\n");
return;
}
struct node *p = head->first;
int n = head->nodeNumbre;
while(n--)
{
printf("%d\t", p->data);
p = p->next;
}
printf("\n");
//printf("链表有%d个节点\n", head->nodeNumbre);
}
int main(int argc, char const *argv[])
{
//创建链表
struct headNode *head = creat_list();
if(head == NULL)
{
printf("create list failed:");
return -1;
}
//修改节点
//head = updata_Node(head,3,5);
//删除节点
//head = removeNode(head,3);
//增加节点
//head = addNode(head,3,4);
//判断链表是否有环
if(circulate(head))
{
printf("该链表有环\n");
}
else
{
printf("该链表没有环\n");
}
//显示链表
show_list(head);
//销毁链表
//destroy_list(head);
//show_list(head);
return 0;
}
表这个思想要好好利用
栈
是一种逻辑结构,也是以一个特殊的线性表,特使在只能固定在一端操作,只要满足上述条件,那么这种特殊的线性表就会呈现出一种"后进先出"的逻辑,这种逻辑就被称为栈
-
栈顶 : 可以进行插入删除的一端。
-
栈底:栈顶的对端。
-
入栈: 将节点插入栈顶之上,也称为压栈,函数名通常为push()。
-
出栈:将节点从栈顶剔除,也称为弹栈,函数名通常额外pop()。
-
取栈顶: 取得栈顶元素,但不出栈,函数名通常为top()。
-
基于这种固定一端操作的简单约定,栈获得了"后进先出"的基本特征。
顺序栈;
顺序存储意味着开辟一块连续的内存用于存储数据节点,一般而言,管理栈数据除了需要一块连续的内存之外,还需要记录栈的总容量、当前栈的元素个数、当前栈顶元素位置,如果有多线程还需要配合互斥锁和信号量等信息,为了方便管理,通常将这些信息统一于一个管理结构体中;
![]()
基本操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef int dataType;
//定义顺序栈管理结构体
typedef struct
{
dataType *data;//指向顺序栈首地址
int size;//顺序栈容量
int top;//栈顶
}seqStack;
//初始化顺序栈
seqStack *init_stack(int size)
{
seqStack *s = malloc(sizeof(seqStack));
if(s == NULL)
return NULL;
s->data = calloc(size, sizeof(dataType));
if(s->data == NULL)
return NULL;
s->size = size;
s->top = -1;
return s;
}
//判断栈满
bool is_full(seqStack *s)
{
return s->top == s->size - 1;
}
//判断栈为空
bool isEmpty(seqStack *s)
{
return s->top == -1;
}
//入栈
bool push(seqStack *s, dataType data)
{
//判断栈是否找满
if(is_full(s))
return false;
s->data[++s->top] = data;
return true;
}
//取栈顶,不出栈
bool top(seqStack *s, dataType *data)
{
if(isEmpty(s))
return false;
//取栈顶元素
*data = s->data[s->top];
return true;
}
//出栈
bool pop(seqStack *s, dataType *data)
{
if(!top(s,data))
{
return false;
}
s->top--;
return true;
}
int main(int argc, char const *argv[])
{
seqStack *s = init_stack(10);
if(s == NULL)
{
printf("init stack failed\n");
return -1;
}
//入栈
while(1)
{
dataType data;
if(scanf("%d", &data) == 0)//退出
break;
push(s,data);
}
//弹栈
for(int i = s->top; i >= 0; i--)
{
dataType data;
pop(s,&data);
printf("%d\t", data);
}
printf("\n");
// while (s->top != -1)
// {
// dataType data;
// pop(s,&data);
// printf("%d\t",data);
// }
// printf("\n");
return 0;
}
链式栈
![]()
基本操作
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef int datatype;
// 数据节点
typedef struct node
{
datatype data;
struct node *next;//指向下一个节点
}node;
// 链式栈管理结构体
typedef struct linkStack
{
node *top; // 链式栈栈顶指针
int size; // 链式栈当前元素个数
}linkStack;
// 初始化链式栈
linkStack * initStack(void)
{
linkStack *s = (linkStack *)malloc(sizeof(linkStack));
if(s == NULL)
{
return NULL;
}
s->top = NULL;
s->size = 0;
return s;
}
// 判断栈是否为空
bool isEmpty(linkStack *s)
{
return (s->size == 0);
}
//创建新节点
node *creat_node(datatype data)
{
node *pnew = malloc(sizeof(node));
if(pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
// 入栈
bool push(linkStack *s, datatype data)
{
// 创建链表节点
node *new = creat_node(data);
if(new == NULL)
return false;
// 将节点置入栈顶,头插
new->next = s->top;
s->top = new;
// 更新栈元素个数
s->size++;
return true;
}
// 取栈顶元素
node *top(linkStack *s)
{
if(isEmpty(s))
return NULL;
return s->top;
}
// 出栈
node *pop(linkStack *s)
{
node *p = top(s);
if(p == NULL)
return NULL;
// 将原栈顶元素剔除出栈
s->top = p->next;
p->next = NULL;
s->size--;
return p;
}
int main(int argc, char const *argv[])
{
//初始化链式栈
linkStack *s = initStack();
if(s == NULL)
return -1;
//入栈
datatype n;
scanf("%d", &n);
while(n)
{
push(s,n % 8);
n = n / 8;
}
// push(s,3);
// push(s,7);
// push(s,1);
//出栈
// while(s->size != 0)
// {
// node *p = pop(s);
// if(p == NULL)
// return -1;
// printf("%d\t", p->data);
// }
while(1)
{
if(isEmpty(s))
{
break;
}
node *p = pop(s);
if(p == NULL)
return -1;
printf("%d\t", p->data);
}
printf("\n");
return 0;
}
队列
概念:
只要满足上述条件,那么这种特殊的线性表就会呈现一种“先进先出”的逻辑,这种逻辑就被称为队列。
-
队头:可以删除节点的一端
-
队尾:可以插入节点的一端
-
入队:将节点插入到队尾之后,函数名通常为enQueue()
-
出队:将队头节点从队列中剔除,函数名通常为outQueue()
-
取队头:取得队头元素,但不出队,函数名通常为front()
由于这种固定两端操作的简单约定,队列获得了“先进先出”的基本特性.
顺序存储的队列循环队列:
顺序存储的队列之所以被称为循环队列,是因为可以利用更新队头队尾的下标信息,来循环地利用整个数组,出队入队时也不必移动当中的数据。
需要牺牲至少数组中的一个存储位置,来区分循环队列中的满队和空队。满队和空队的约定如下:
-
当front与rear相等时,队列为空
-
当rear循环加一与front相等时,队列为满
与其他数据结构一样,管理循环队列除了需要一块连续的内存之外,还需要记录队列的总容量、当前队列的元素个数、当前队头、队尾元素位置,如果有多线程还需要配互斥锁和信号量等信息,为了便于管理,通常将这些信息统一于在一个管理结构体之中。
基本操作:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int dataType;
typedef struct
{
dataType *data;//循环队列入口
int cap;//队列总容量
int front;//队头元素下标
int rear;//队尾元素下标
}seqQueue;
//初始化队列
seqQueue *init_seqQueue(int size)
{
seqQueue *sq = malloc(sizeof(seqQueue));
if(sq == NULL)
return NULL;
sq->data = calloc(size, sizeof(dataType));
if(sq->data == NULL)
return NULL;
sq->cap = size;
sq->front = sq->rear = 0;
}
//判断队列是否满
bool is_full(seqQueue *sq)
{
return (sq->rear + 1) % sq->cap == sq->front;
}
//判断队列为空
bool is_empty(seqQueue *sq)
{
return sq->front == sq->rear;
}
//入队
bool enQueue(seqQueue *sq, dataType data)
{
//队列是否为满
if(is_full(sq))
{
return false;
}
//入队,尾进
sq->data[sq->rear] = data;
sq->rear = (sq->rear + 1) % sq->cap;
return true;
}
//出队
bool outQueue(seqQueue*sq, dataType *data)
{
if(is_empty(sq))
{
return false;
}
*data = sq->data[sq->front];
sq->front = (sq->front + 1) % sq->cap;
return true;
}
//显示
void show(seqQueue *sq)
{
for(int i = sq->front; i != sq->rear; i = ((i + 1) % sq->cap))
{
printf("%d\t",sq->data[i]);
}
printf("\n");
}
int main(int argc, char const *argv[])
{
//初始化队列
seqQueue *sq = init_seqQueue(5);
if(sq == NULL)
return -1;
while(1)
{
dataType data;
if(scanf("%d", &data) == 1)
{
if(enQueue(sq,data) == false)
{
printf("队满,无法入队\n");
continue;
}
}
else
{
//清空缓冲区
while(getchar() != '\n');
if(!outQueue(sq,&data))
{
printf("队列为空\n");
break;
}
}
show(sq);
}
return 0;
}
链式队列
![]()
基本操作:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int dataType;
//数据节点
typedef struct node
{
dataType data;
struct node *next;
}node;
//管理结构体
typedef struct linkQueue
{
struct node *fron;//头节点
struct node *rear;//尾节点
int size;//节点数
}linkQueue;
//舒适化管理结构体
linkQueue *init_linkQueue()
{
linkQueue *lq = malloc(sizeof(linkQueue));
if(lq == NULL)
return NULL;
lq->fron = NULL;
lq->rear = NULL;
lq->size = 0;
return lq;
}
//创建新节点
node *creat_node(dataType data)
{
node *pnew = malloc(sizeof(dataType));
if(pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
//队列为空
bool is_empty(linkQueue *lq)
{
return lq->size == 0;
}
//入队
bool enQueue(linkQueue *lq, dataType data)
{
//创建新节点
node *pnew = creat_node(data);
if(pnew == NULL)
return false;
//从无到有
if(is_empty(lq))
{
lq->fron = lq->rear = pnew;
}
else
{
lq->rear->next = pnew;
lq->rear = pnew;
}
lq->size++;
return true;
}
//取队头元素,不出队
bool front(linkQueue *lq, dataType *data)
{
if(is_empty(lq))
return false;
*data = lq->rear->data;
return true;
}
//出队
bool outQueue(linkQueue *lq, dataType *data)
{
if(!front(lq,data))
return false;
//将头节点剔除
//如果链表只有一个节点
if(lq->size == 1)
{
free(lq->fron);
lq->fron = NULL;
lq->rear = NULL;
}
else
{
node *tmp = lq->fron;
lq->fron = tmp->next;
tmp->next = NULL;
free(tmp);
}
lq->size--;
return true;
}
//显示
void show(linkQueue *lq)
{
printf("队列里有元素:\t");
for(node *p = lq->fron; p != NULL; p = p->next)
{
printf("%d\t",p->data);
}
printf("\n");
}
int main(int argc, char const *argv[])
{
//初始化管理结构体
struct linkQueue *lq = init_linkQueue(5);
if(lq == NULL)
{
return -1;
}
while(1)
{
dataType data;
printf("请输入:");
if(scanf("%d", &data) == 1)
{
if(enQueue(lq,data) == false)
{
continue;
}
}
else
{
//清空缓冲区
while(getchar() != '\n');
if(!outQueue(lq,&data))
{
printf("队列为空\n");
break;
}
}
show(lq);
}
return 0;
}
这些就是我这周的学习总结,这些结构需要的逻辑思维很强,学的很费力,每天都需要复习到很晚,不过现在感觉好多了。