【1-1】创建一个静态的顺序表存放整数,大小为10,完成以下的操作。
// 实例1-1 2023年12月21日15点59分-16点31分
# include <stdio.h>
# define MaxSize 10
// 静态顺序表的各种操作
// 向顺序表插入元素,Sqlist表首地址,*len表的长度,pos插入元素的位置,x待插入的元素值
void insertElem(int Sqlist[], int * len, int pos, int x)
{
if (pos < 1 || pos > *len+1 || *len==MaxSize) { // 非法插入
printf("This insert is illegal\n");
return ;
}
for (int i = *len-1; i >= pos-1; --i) // 将第pos个位置及以后的元素顺序后移一个元素的位置
Sqlist[i+1] = Sqlist[i];
Sqlist[pos-1] = x; // 在第pos个位置上插入元素x
(*len)++; // 表长加1
}
// 从顺序表中删除元素,Sqlist表首地址,*len表的长度,pos删除元素的位置
void deleteElem(int Sqlist[], int *len, int pos)
{
if (pos < 1 || pos > *len) { // 非法删除
printf("This delete is illegal\n");
return ;
}
for (int i = pos; i < *len; ++i) // 将第pos个位置及以后的元素一次前移
Sqlist[i-1] = Sqlist[i];
(*len)--; // 表长减1
}
int main()
{
int Sqlist[MaxSize]; // 定义一个静态顺序表
int len = 0;
for (int i = 0; i < 6; ++i) { // 从键盘输入6个整数
int num;
printf("Please input %dth number:", i+1);
scanf("%d", & num);
insertElem(Sqlist, & len, i+1, num);
}
printf("Print the result:"); // 输出顺序表的所有整数
for (int i = 0; i < len; ++i)
printf("%d ", Sqlist[i]);
printf("\nThe spare length is %d\n", MaxSize - len); // 显示表中的剩余空间
insertElem(Sqlist, & len, 3, 0); // 在表中第3个位置插入整数0
printf("Print the result:"); // 输出顺序表的所有整数
for (int i = 0; i < len; ++i)
printf("%d ", Sqlist[i]);
printf("\nThe spare length is %d\n", MaxSize - len); // 显示表中的剩余空间
insertElem(Sqlist, & len, 11, 0); // 在表中第11个位置插入整数0
deleteElem(Sqlist, & len, 6); // 删除表中第6个位置元素
printf("Print the result:"); // 输出顺序表的所有整数
for (int i = 0; i < len; ++i)
printf("%d ", Sqlist[i]);
printf("\nThe spare length is %d\n", MaxSize - len); // 显示表中的剩余空间
deleteElem(Sqlist, & len, 16); // 删除表中第16个位置元素
return 0;
}
总结:静态顺序表的插入和删除元素,一方面需要判断是否非法操作,另一方面相应移动元素,表长也相应改变!
【1-2】编写程序,动态地创建一个顺序表。
// 1-2 2023年12月21日16点42分-17点13分
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>
# define MaxSize 10
typedef int ElemType; // 将int定义为ElemType
typedef struct {
int *elem; // 顺序表的首地址
int length; // 顺序表中表的长度
int listsize; // 顺序表的存储空间容量
}Sqlist;
// 初始化一个顺序表,Sqlist类型的指针
void initSqlist(Sqlist *L)
{
L->elem = (int*)malloc(MaxSize * sizeof(ElemType));
if (!L->elem)
exit(0);
L->length = 0;
L->listsize = MaxSize;
}
// 向顺序表中插入元素,Sqlist类型的指针,pos插入元素的位置,x插入的元素
void insertElem(Sqlist *L, int pos, ElemType x)
{
if (pos < 1 || pos > L->length + 1) { // 非法插入
printf("\nThis insert is illegal");
// exit(0);
return ;
}
if (L->length >= L->listsize) {
ElemType * base = (ElemType *)realloc(L->elem, (L->listsize+10) * sizeof(ElemType));
L->elem = base; // 更新内存基址
L->listsize += 100; // 存储空间增大100个单元
}
for (ElemType * p = &(L->elem[L->length-1]); p >= &(L->elem[pos-1]); --p) // 将第pos个位置及以后的元素后移
*(p+1) = *p;
L->elem[pos - 1] = x; // 在第pos个位置上插入元素x
++L->length; // 表长加1
}
// 从顺序表删除元素,Sqlist类型的指针,pos删除元素的位置
void deleteElem(Sqlist *L, int pos)
{
if (pos < 1 || pos > L->length) {// 非法删除
printf("\nThis Delete is illegal");
exit(0);
}
for (ElemType * p = &(L->elem[pos-1]); p <= L->elem+L->length-1; ++p)
*(p-1) = *p;
--L->length; // 表长减1
}
int main()
{
Sqlist l;
initSqlist(&l); // 初始化一个顺序表
for (int i = 0; i < 15; ++i) // 插入元素
insertElem(&l, i+1, i+1);
printf("\nThe content of the list is\n");
for (int i = 0; i < l.length; ++i) // 打印元素
printf("%d ", l.elem[i]);
deleteElem(&l, 5); // 删除第5个元素
printf("\nDelete the fifth element\n");
for (int i = 0; i < l.length; ++i)
printf("%d ", l.elem[i]);
insertElem(&l, -1, 12);
deleteElem(&l, -1);
return 0;
}
总结:动态顺序表的插入和删除元素,一方面需要判断是否非法操作,另一方面相应移动元素,表长也相应改变!另外,注意动态内存的使用。
【1-3】编写程序实现对链表的操作。要求:从终端输入一组整数,以0作为结束标志,将这一组整数存放在一个链表中(结束标志0不包括在内),打印出该链表中的值。然后删除该链表中的第5个元素,打印出删除后的结果。最后在内存中释放掉该链表。
//1-3 2023年12月30日09点32分-11点32分
//删除链表结点出错,一点都不认真,书上的for循环后面是;不要想当然的写
//要思考
# include <stdio.h>
# include <malloc.h>
typedef int ElemType;
typedef struct node{
ElemType data; //数据域
struct node *next; //指针域
}LNode, *LinkList;
//创建一个链表
LinkList createLinkList(int n)
{
//建立一个长度为n的链表
LinkList p, r, list = NULL;
ElemType e;
for (int i = 1; i <= n; i++) {
scanf("%d", &e); //输入结点的内容
/*用malloc函数在内存的动态存储区开辟一块大小为sizeof(LNode)的空间,
并将其地址赋值给LinkList类型的变量p*/
p = (LinkList)malloc(sizeof(LNode));
p->data = e; //将数据e存入该结点的数据域data
p->next = NULL; //指针域存放NULL
/*如果指针变量list为空,说明本次生成的结点为第一个结点,所以将p赋值给list,
list是LinkList类型变量,只用来指向第一个链表结点,因此它是该链表的头指针,最后要返回*/
if (!list)
list = p; //赋值链表头指针
/*如果指针变量list不为空,则说明本次生成的结点不是第一个结点,因此将p赋值给r->next。
这里r是一个LinkList类型变量,它永远指向原先链表的最后一个结点,也就是要插入结点的前一个结点*/
else
r->next = p; //将结点连入链表
/*再将p赋值给r,目的是使r再次指向最后的结点,以便生成链表的下一个结点,即保证r永远指向原先链表的最后一个结点*/
r = p;
}
/*最后将生成的链表的头指针list返回主调函数,通过list就可以访问到该链表的每一个结点,并对该链表进行操作*/
return list; //返回链表头指针
}
void insertList(LinkList *list, LinkList q, ElemType e)
{
//向链表中由指针q指出的结点后面插入结点,结点数据为e
LinkList p;
p = (LinkList)malloc(sizeof(LNode)); //生成一个新结点,由p指向它
p->data = e; //向该结点的数据域赋值e
if (!*list) {
*list = p;
p->next = NULL;
} else {
p->next = q->next;
q->next = p;
}
}
void delLink(LinkList *list, LinkList q)
{
//删除链表的某结点
LinkList r;
printf("打印\n");
LinkList tmp = *list;
while (tmp) {
printf("tmp = %p, tmp->next = %p\n", tmp, tmp->next);
tmp = tmp->next;
}
if (q == *list) {
*list = q->next;
free(q);
} else {
//遍历链表,找到q的前驱结点的指针
/*r = *list;
printf("r = %p, r->data = %d, r->next = %p\n", r, r->data, r->next);
printf("q = %p, q->data = %d\n", q, q->data);
if (r->next == q) {
printf("相等\n");
} else {
printf("不相同\n");
}
while (r->next != q) {
r = r->next;
}
r->next = q->next;
free(q);*/
for (r = *list; r->next != q; r = r->next) {
/*printf("r = %p, r->next = %p\n", r, r->next);
if (r->next != NULL) {
r->next = q->next;
free(q);
}*/
}
if (r->next != NULL) {
r->next = q->next;
free(q);
}
}
}
void destroyLinkList(LinkList *list)
{
//销毁一个链表list
LinkList p, q;
p = *list; //首先将*list的内容赋值给p,这样p也指向链表的第一个结点,成为了链表的表头
/*判断只要p不为空(NULL),就将p指向的下一个结点的指针(地址)赋值给q,并应用函数free()释放掉p所指向的结点,
p再指向下一个结点。如此循环,直到链表为空为止*/
while (p) {
q = p->next;
free(p);
p = q;
}
/*最后将*list的内容置为NULL,这样主函数中的链表list就为空了,防止了list变为野指针。而且链表在内存中也被完全地释放掉了*/
*list = NULL;
}
int main()
{
LinkList l, q;
q = l = createLinkList(1); //创建一个链表结点,q和l指向该结点
int e;
scanf("%d", &e); //循环地输入数据,同时插入新生成的结点
while (e) {
insertList(&l, q, e);
q = q->next;
scanf("%d", &e);
}
q = l;
printf("The content of the linklist\n");
while (q) {
printf("%d ", q->data); //输出链表中的内容
q = q->next;
}
q = l;
printf("l = %p\n", l);
printf("\nDelete the fifth element\n");
for (int i = 0; i < 4; i++) { //将指针q指向链表第5个元素
q = q->next;
printf("here q = %p, q->next = %p\n", q, q->next);
}
printf("q->data = %d, q = %p\n", q->data, q);
printf("l = %p\n", l);
delLink(&l, q); // 删除q所指的结点
q = l;
while (q) {
printf("%d ", q->data); //打印删除后的结果
q = q->next;
}
destroyLinkList(&l); //释放掉该链表
return 0;
}
🍎总结:链表的创建、插入和删除元素、销毁,要认真思考,能独立写出来。认真细心哦,书上的删除结点代码里面的for循环是空语句,以分号结尾,我却一直没有发现,找了好长时间的错误,要细心啊。在debug过程中,我查看了链表的每个结点的地址,之前没有看到地址,一直想的都是书上描述的内容,现在通过发现链表还真是每个结点链接在一起,还是很有意思的,哈哈哈。动脑子编写程序哦,不要一味的抄袭。
【1-4】利用栈的数据结构,将二进制数转换为十进制数。
//1-4 2023年12月30日15点35分-16点38分
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>
# include <math.h>
//# define ElemType int
typedef char ElemType; //两种方式注意区分哦
typedef struct { //定义了一个顺序栈类型
ElemType *base; //base是指向栈底的指针变量
ElemType *top; //top是指向栈顶的指针变量
int stacksize; //stacksize指示栈的当前可使用的最大容量
/*可以通过base和top对栈进行各种操作,通过stacksize判断栈的空间分配情况*/
}sqStack;
//创建一个栈
/*创建一个栈有两个任务:一是在内存中开辟一段连续的空间,用作栈的物理存储空间;二是将
栈顶、栈底地址赋值给sqStack类型变量(对象)的top和base域,并设置stacksize值,以便通过
这个变量(对象)对栈进行各种操作*/
//sqStack *createsqStack(void) //这样写有问题,先看书上的答案,一会儿再来改
//{
// printf("创建一个栈!\n");
// sqStack *sq;
// sq = (sqStack*)malloc(sizeof(sqStack) * 100);
// if (sq == NULL) {
// printf("创建失败!\n");
// exit(0);
// }
// sq->stacksize = 100;
// printf("创建成功!\n");
// return sq;
//}
# define STACK_INIT_SIZE 100
void initStack(sqStack *s)
{
/*在内存中开辟一段连续空间作为栈空间,首地址赋值给s->base*/
s->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
if (!s->base) //分配空间失败
exit(0);
s->top = s->base; //最开始,栈顶就是栈底
s->stacksize = STACK_INIT_SIZE; //最大容量为STACK_INIT_SIZE
printf("空栈时s->base = s->top = %p, s->stacksize = %d\n", s->top, s->stacksize);
}
//入栈操作
# define STACKINCREMENT 10
void push(sqStack *s, ElemType e)
{
if (s->top - s->base >= s->stacksize) {
//栈满,追加空间
s->base = (ElemType *)realloc(s->base, (s->stacksize +
STACKINCREMENT)*sizeof(ElemType));
if (!s->base) exit(0); //存储分配失败
s->top = s->base + s->stacksize;
s->stacksize = s->stacksize + STACKINCREMENT; //设置栈的最大容量
}
printf("当前s->top = %p,插入元素e = %c,", s->top, e);
*(s->top) = e; //放入数据
s->top++;
printf("插入元素后s->top = %p\n", s->top);
}
//出栈操作
void pop(sqStack *s, ElemType *e)
{
if (s->top == s->base) {
printf("空栈,没有元素可以出栈!\n");
return ;
}
printf("当前s->top = %p,", s->top);
*e = *--(s->top);
printf("出栈元素e = %c,删除元素后s->top = %p\n", *e, s->top);
}
//清空一个栈
void clearStack(sqStack *s)
{
printf("清空栈之前s->top = %p, s->base = %p\n", s->top, s->base);
s->top = s->base;
printf("清空栈s->top = s->base = %p\n", s->top);
}
//销毁一个栈
void destroyStack(sqStack *s)
{
// int len = s->stacksize; //感觉书上这里有错误诶
// printf("len = %d\n", len);
// for (int i = 0; i < len; i++) {
// printf("销毁栈s->base = %p,", s->base);
// free(s->base);
// s->base++;
// printf("此时栈底s->base = %p\n", s->base);
// }
free(s->base);
printf("销毁栈s->base = %p,", s->base);
s->base = s->top = NULL;
printf("此时栈底s->base = %p\n", s->base);
s->stacksize = 0;
}
//计算栈的当前容量
int stackLen(sqStack s)
{
return (s.top - s.base);
}
int main()
{
// sqStack *s = createsqStack();
sqStack s;
printf("Please input a binary digit\n");
initStack(&s); //创建一个栈,用来存放二进制字符串
//输入0/1字符表示的二进制数,以#结束
ElemType c;
scanf("%c", &c);
while (c != '#') {
push(&s, c);
scanf("%c", &c);
}
getchar();
int len = stackLen(s); //得到栈中的元素个数,即二进制数的长度
int sum = 0;
for (int i = 0; i < len; i++) {
pop(&s, &c);
sum += (c-'0') * pow(2, i); //转换为十进制
}
printf("Decimal is %d\n", sum);
// clearStack(&s);
// pop(&s, &c);
// destroyStack(&s);
// pop(&s, &c);
return 0;
}
🍎总结:栈的创建、插入和删除元素、销毁,要认真思考,能独立写出来。
【1-5】实现一个链队列,任意输入一串字符,以@为结束标志,然后将队列中的元素逐一取出,打印在屏幕上。
//1-5 2023年12月31日11点01分-11点37分
//队列中每个元素的类型
# include <malloc.h>
# include <stdlib.h>
# include <stdio.h>
typedef char ElemType;
typedef struct QNode{
ElemType data;
struct QNode* next;
}QNode, *QueuePtr;
//队列类型
typedef struct{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
//创建一个队列
void initQueue(LinkQueue *q)
{
//初始化一个空队列
q->front = q->rear = (QueuePtr)malloc(sizeof(QNode));
//创建一个头结点,队头队尾指针指向该结点
if (!q->front) exit(0); //创建头结点失败
q->front->next = NULL; //头结点指针域置NULL
printf("初始化一个空队列:\nq->front = q->rear = %p\n", q->front);
printf("q->front->next = %p, q->front->data = %d, "
"(*(q->front)).data = %d\n", q->front->next, q->front->data, (*(q->front)).data);
}
//入队列
void enQueue(LinkQueue *q, ElemType e)
{
QueuePtr p = (QueuePtr)malloc(sizeof(QNode)); //创建一个队列元素的结点
if (!q->front) exit(0); //创建头结点失败
p->data = e;
p->next = NULL;
printf("插入元素%c, p = %p, p->data = %c, p->next = %p, q->rear = %p\n", e, p, p->data, p->next, q->rear);
q->rear->next = p;
printf(" q->rear->next = %p, ", q->rear->next);
q->rear = p;
printf("q->rear = %p\n", q->rear);
}
//出队列
void deQueue(LinkQueue *q, ElemType *e)
{ //如果队列q不为空,删除q的队头元素,用e返回其值
if (q->front == q->rear) return ; //队列为空,返回
QueuePtr p = q->front->next;
*e = p->data;
q->front->next = p->next;
if (q->rear == p) q->rear = q->front; //如果队头就是队尾,则修改队尾指针
free(p);
}
//销毁队列
void destroyQueue(LinkQueue *q)
{
while (q->front) {
q->rear - q->front->next;
free(q->front);
q->front = q->rear;
}
}
int main()
{
ElemType e;
LinkQueue q;
initQueue(&q); //初始化一个队列q
printf("Please input a string into a queue\n");
scanf("%c", &e);
while (e != '@') {
enQueue(&q, e); //向队列中输入字符串,以@表示结束
scanf("%c", &e);
}
printf("The string into the queue is\n");
while (q.front != q.rear) { //将队列中的元素出队列,并打印在屏幕上
deQueue(&q, &e);
printf("%c", e);
}
return 0;
}
【1-6】用先序序列创建一棵二叉树,并输出字符D位于二叉树的层数。
//1-6 2023年12月31日15点07分-15点51分
# include <stdio.h>
# include <stdlib.h>
//# include <malloc.h>
typedef char ElemType;
typedef struct BiTNode{ //二叉树的结点
ElemType data; //结点的数据域
struct BiTNode *lchild, *rchild; //指向左孩子和右孩子
}BiTNode, *BiTree;
//访问二叉树结点,输出包含D字符结点位于二叉树中的层数
void visit(char c, int level)
{
if (c == 'D') {
printf("%c is at %d level of BiTree\n", c, level);
}
}
//遍历二叉树
void PreOrderTraverse(BiTree T, int level)
{
if (T) { //递归结束条件,T为空
visit(T->data, level); //访问根结点
PreOrderTraverse(T->lchild, level+1); //先序遍历T的左子树
PreOrderTraverse(T->rchild, level+1); //先序遍历T的右子树
}
}
/*void visit(ElemType e)
{
printf("%c", e);
}*/
//先序遍历
/*void PreOrderTraverse(BiTree T)
{
if (T) { //递归结束条件,T为空
visit(T->data); //访问根结点
PreOrderTraverse(T->lchild); //先序遍历T的左子树
PreOrderTraverse(T->rchild); //先序遍历T的右子树
}
}*/
//中序遍历
/*void InOrderTraverse(BiTree T)
{
if (T) { //递归结束条件,T为空
InOrderTraverse(T->lchild); //中序遍历T的左子树
visit(T->data); //访问根结点
InOrderTraverse(T->rchild); //中序遍历T的右子树
}
}*/
//后序遍历
/*void PostOrderTraverse(BiTree T)
{
if (T) { //递归结束条件,T为空
PostOrderTraverse(T->lchild); //后序遍历T的左子树
PostOrderTraverse(T->rchild); //后序遍历T的右子树
visit(T->data); //访问根结点
}
}*/
//先序序列创建一棵二叉树
void CreateBiTree(BiTree *T)
{
char c;
scanf("%c", &c);
if (c == ' ') *T = NULL;
else {
*T = (BiTree)malloc(sizeof(BiTNode)); //创建根结点
(*T)->data = c; //向根结点中输入数据
CreateBiTree(&((*T)->lchild)); //递归地创建左子树
CreateBiTree(&((*T)->rchild)); //递归地创建右子树
}
}
int main()
{
int level = 1;
BiTree T = NULL; //最开始T指向空
CreateBiTree(&T); //创建二叉树
PreOrderTraverse(T, level); //遍历二叉树,找到包含D字符结点位于二叉树中的层数
return 0;
}
【1-7】用邻接表存储的形式创建无向图,并应用深度优先搜索的方法遍历该图中的每个顶点,打印出每个顶点中包含的数据。
//1-7 2023年12月31日16点02分-16点37分
# include <stdio.h>
# include <malloc.h>
//邻接表
# define MAX_VERTEX_NUM 20
typedef struct ArcNode{ //单链表中的结点的类型
int adjvex; //该边指向的顶点在顺序表中的位置
struct ArcNode *next; //下一条边
// infoType *weight; //边上的权重,可省略
}ArcNode;
typedef struct VNode{ //顶点类型
// VertexType data; //顶点中的数据信息
int data; //顶点中的数据信息
ArcNode *firstarc; //指向单链表,即指向第一条边
}VNode;
//VNode G[MAX_VERTEX_NUM]; //VNode类型的数组G,它是图的存储容器
int visited[5] = {0, 0, 0, 0, 0};
//图的创建
void CreateGraph(int n, VNode G[])
{
printf("Input the information of the vertex\n");
for (int i = 0; i < n; i++) {
// Getdata(G[i]); //得到每个顶点中的数据
scanf("%d", &G[i]);
G[i].firstarc = NULL; //初始化第一条边为空
}
int e;
ArcNode *q;
for (int i = 0; i < n; i++) {
printf("Create the edges for the %dth vertex\n", i);
scanf("%d", &e);
while (e != -1) {
ArcNode *p = (ArcNode *)malloc(sizeof(ArcNode)); //创建一条边
p->next = NULL;
p->adjvex = e;
if (G[i].firstarc == NULL) G[i].firstarc = p; //i结点的第一条边
else q->next = p; //下一条边
q = p;
scanf("%d", &e);
}
}
}
int FirstAdj(VNode G[], int v)
{
if (G[v].firstarc != NULL)
return (G[v].firstarc)->adjvex;
return -1;
}
int NextAdj(VNode G[], int v)
{
ArcNode *p;
p = G[v].firstarc;
while (p != NULL) {
if (visited[p->adjvex])
p = p->next;
else
return p->adjvex;
}
return -1;
}
//深度优先搜索一个连通图
void DFS(VNode G[], int v)
{
int w;
// visit(v); //访问当前顶点
printf("%d ", G[v].data); //访问当前顶点,打印出该顶点中的数据信息
visited[v] = 1; //将顶点v对应的访问标记置1
w = FirstAdj(G, v); //找到顶点v的第一个邻接点,如果无邻接点,返回-1
while (w != -1) {
if (visited[w] == 0) //该顶点未被访问
DFS(G, w); //递归地进行深度优先搜素
w = NextAdj(G, v); //找到顶点v的下一个邻接点,如果无邻接点,返回-1
}
}
int main()
{
VNode G[5];
CreateGraph(5, G);
printf("DFS Travel this undirected graph\n");
DFS(G, 0);
return 0;
}
总结:要加油啊!!!