-
这篇文章主要是数据结构算法,而不是说明数据结构这里面的内容
我本身也非科班,学习数据结构时确实觉得很抽象,但用代码来看觉得理解了一些,学习数据结构前C语言或C++这两门要有一门,不然可能看不懂,JAVA不清楚,我还没学JAVA
全新版本,会更下去,因为复习到408了,希望考408的当做没看到(开玩笑的,加油一起上岸)
主要参考王道主要代码,以及up freedomじゆう,大部分是学习代码,带*的是我个人编写,可能有BUG,其他的也是手写,不过可能会根据我个人情况全部统一一个格式。
参考用书:《数据结构 C语言版 第2版》严蔚敏
基本会把数据结构全部代码全部整合,C++只会用到引用&,循环体内直接定义,因为C需要指针,比较麻烦,其他都是用C语言
408是允许C和C++(请自己核对是否为真),如果考C语言程序设计这门课程那就不能用&和直接定义(严格点的学校可能不给分),只能用*和循环体外先定义变量,请确认课程是否允许使用C++
个人水平有限,有错误麻烦帮忙指正
printf类函数 判断类条件 主要为了健壮性和可读性,考试不写应该没什么问题(个人观点)
-
如何运行文内代码?
1.复制全局变量代码,粘贴到能运行C++的环境(C语言环境需要将引用,取值操作改成指针)
2.复制想要运行的代码,粘贴到能运行C++的环境
3.运行
全局变量/宏定义
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef int Status;
#define MAXSIZE 10
#define TRUE 1
#define FALSE 0
#define ERROR 0
#define OVERFLOW -2
#define OK 1
顺序表(Sequence List)静态分配
//顺序表静态分配
typedef struct{
ElemType data[MAXSIZE];
int length;
}SqList;
//初始化
void InitList(SqList &L)
{
for (int i = 0; i < MAXSIZE; i++)
L.data[i] = 0;
L.length = 0;
}
//插入
int ListInsert(SqList &L, ElemType i, ElemType e)
{
if (i < 1 || i > L.length + 1)
return ERROR;
if (L.length >= MAXSIZE)
return ERROR;
for (int j = L.length; j >= i; j--)
L.data[j] = L.data[j - 1];
L.data[i - 1] = e;
L.length++;
return OK;
}
//按位删除
int ListDelete(SqList &L, ElemType i, ElemType &e)
{
if (i < 1 || i > L.length)
return ERROR;
e = L.data[i - 1]; //王道这里是按位删除,e值带出
for (int j = i; j < L.length; j++)
L.data[j - 1] = L.data[j];
L.length--;
return OK;
}
//按值删除*
int ValueDelete(SqList &L, ElemType e)
{
for (int i = 0; i <= L.length; i++) //从下标0到L.length 最先找到的就删除
{
if (e == L.data[i - 1]) // 也可用[j+1] = [j] 条件变成length-1
{
for (int j = i; j <= L.length; j++)
L.data[j - 1] = L.data[j];
L.length--;
printf("The value has been deleted.\n");
return OK;
}
}
printf("Can not find the value.\n");
return ERROR;
}
//按位查找(获取元素)
Status GetElem(SqList L, int i)
{
return L.data[i - 1];
}
//按值查找(查找元素)*
int GetValue(SqList L, ElemType e)
{
for (int i = 0; i <= L.length; i++)
{
if (e == L.data[i - 1])
return i - 1;
}
return ERROR;
}
//遍历*
void PrintList(SqList &L)
{
for (int i = 0; i < L.length; i++)
{
printf("data[%d] = %d\n", i, L.data[i]);
}
if (L.length > 0)
printf("SqList length = %d\n",L.length);
}
//main函数,主要用来调用函数
int main()
{
SqList L;
InitList(L);
PrintList(L);
ListInsert(L, 1, 2);
ListInsert(L, 2, 3);
ListInsert(L, 3, 4);
PrintList(L);
int e = -1;
ListDelete(L, 3, e);
PrintList(L);
int x = GetElem(L, 2); //这里是根据位置,返回值
printf("L.data[x] = %d\n", x); //GetElem 值
ListInsert(L, 3, 5);
PrintList(L);
ValueDelete(L, 5);
PrintList(L);
ListInsert(L, 3, 5);
x = GetValue(L, 5); //根据值,返回第一个搜索位置
printf("L.data[x] = %d\n", x);
return 0;
}
---7,22 2022更新
顺序表(Sequence List)动态分配
静态分配和动态分配主要在 定义结构体、初始化、增加长度(扩容)有区别
静态分配类似先固定大小,动态分配类似用多少分配多少
主要在于理解 malloc() 这个函数意义,链表也会用到
//顺序表动态分配
typedef struct{
ElemType *data;
int max; //最大容量,这个变量是为了扩容用的
int length;
}SeqList;
//初始化
int InitSeqList(SeqList &L)
{
L.data = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE); //C++可以用new 这条语句是向内存申请分配空间
if (!L.data)
return OVERFLOW;
L.length = 0;
L.max = MAXSIZE;
return OK;
}
//获取元素
Status GetElem(SeqList L, int i)
{
return L.data[i - 1];
}
//查找元素
int LocateElem(SeqList L, ElemType e)
{
for (int i = 0; i <= L.length; i++)
{
if (e == L.data[i - 1])
return i - 1;
}
return ERROR;
}
//插入
int SeqlInsert(SeqList &L, int i, ElemType e)
{
if (i < 1 || i > L.length + 1)
return ERROR;
if (L.length >= L.max)
return ERROR;
for (int j = L.length; j >= i; j--)
L.data[j] = L.data[j - 1];
L.data[i - 1] = e;
L.length++;
return OK;
}
//按位删除
int SeqlDelete(SeqList &L, ElemType i, ElemType &e)
{
if (i < 1 || i > L.length)
return ERROR;
e = L.data[i - 1];
for (int j = i; j < L.length; j++)
L.data[j - 1] = L.data[j];
L.length--;
return OK;
}
//遍历*
void PrintList(SeqList &L)
{
for (int i = 0; i < L.length; i++)
{
printf("data[%d] = %d\n", i, L.data[i]);
}
if (L.length > 0)
printf("SeqList length = %d\n", L.length);
}
//增加动态数组的长度
void IncreaseSize(SeqList &L, int len)
{
ElemType *p = L.data;
L.data = (ElemType*)malloc((L.max + len)*sizeof(ElemType));
for (int i = 0; i < L.length; i++)
L.data[i] = p[i];
L.max = L.max + len;
free(p); //释放内存空间
}
//销毁
int SeqlDestroy(SeqList &L)
{
if (!L.data)
return ERROR;
else{
free(L.data);
return OK;
}
}
int main()
{
SeqList L;
InitSeqList(L);
SeqlInsert(L, 1, 2);
SeqlInsert(L, 1, 6);
SeqlInsert(L, 2, 10);
SeqlInsert(L, 2, 10);
SeqlInsert(L, 2, 10);
SeqlInsert(L, 2, 10);
SeqlInsert(L, 2, 10);
SeqlInsert(L, 2, 10);
SeqlInsert(L, 2, 10);
SeqlInsert(L, 2, 11);
PrintList(L);
IncreaseSize(L, 5);
SeqlInsert(L, 2, 13);
SeqlInsert(L, 3, 15);
SeqlInsert(L, 2, 17);
PrintList(L);
int e = -1;
SeqlDelete(L, 2, e);
PrintList(L);
printf("GetElem = %d\n", GetElem(L, 1));
printf("LocateElem = %d\n", LocateElem(L, 2));
return 0;
}
---7,23 2022更新
单链表(Single Linked List)
链表是线性表的重点,默认是带头结点,无头结点的只有一个插入函数,有标注
其中头插法和尾插法非王道版本,参考的是freedomじゆう,可以对比看看
//单链表
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
//LNode *L == LinkList L; 等价
//Lnode *temp = (LNode*)malloc(sizeof(LNode)); 新建结点
//L = NULL; 不带头结点
//初始化带头结点单链表
int InitList(LinkList &L)
{
L = (LNode*)malloc(sizeof(LNode));
if (L == NULL) //内存不足的情况
return FALSE;
L->next = NULL; //头结点指向NULL
return OK;
}
//按位插入
int ListInsert(LinkList &L, int i, ElemType e)
{
if (i < 1)
return FALSE;
LNode *pre; // Previous 指针 指向插入前一个结点
int j = 0;
pre = L; //L 头结点
while (pre != NULL && j < i - 1) //pre找到了i前一个结点
{
pre = pre->next; //从第一个开始找 找不到就下一个结点
j++;
}
if (pre == NULL)
return FALSE;
LNode *s = (LNode*)malloc(sizeof(LNode)); //找到了,新建一个结点
s->data = e; //1.先将插入结点赋值
s->next = pre->next; //2.将i前一个结点的next指针赋值给插入结点
pre->next = s; //3.把i前一个结点指向新建结点
return OK;
}
//不带头结点插入
int NListInsert(LinkList &L, int i, ElemType e)
{
if (i < 1)
return FALSE;
if (i == 1)
{ //多加一段判断位置为1的情况 其他没有改变
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = L;
L = s;
return OK;
}
LNode *pre;
int j = 0;
pre = L;
while (pre != NULL && j < i - 1)
{
pre = pre->next;
j++;
}
if (pre == NULL)
return FALSE;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = pre->next;
pre->next = s;
return OK;
}
//指定结点尾插
int InsertNextNode(LNode *p, ElemType e) //需要传入指定结点
{
if (p == NULL)
return FALSE;
LNode *s = (LNode*)malloc(sizeof(LNode));
if (s == NULL)
return FALSE;
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
//指定结点前插
int InsertPriorNode(LNode *p, ElemType e)
{
if (p == NULL)
return FALSE;
LNode *s = (LNode*)malloc(sizeof(LNode));
if (s == NULL)
return FALSE;
s->next = p->next; //原先p指向的next s也指向p的next
p->next = s; //p->next指向s p-s-x 现在是这样
s->data = p->data; //把原先p的data值给s
p->data = e; //把新赋值给到p 这样原先p的data&next都给到s了 s就是原先的p
return OK;
}
//头插法建立链表(非王道版)
void HeadCreatList(LinkList L, int n)
{
printf("Please input %d numbers and Separate with SPACE\n", n);
for (int i = 0; i < n; i++)
{ //这里是手动键盘输入数据
LNode *p = (LNode*)malloc(sizeof(LNode));
int data;
scanf("%d", &data);
p->data = data;
p->next = L->next;
L->next = p;
}
}
//尾插法建立链表(非王道版,王道版是头结点建立包含在里面)
void TailCreatList(LinkList L, int n)
{
printf("Please input %d numbers and Separate with SPACE\n", n);
LNode *s, *r;
r = L; //定义个指针指向头结点,此时头结点是终端结点
for (int i = 0; i < n; i++)
{
LNode *s = (LNode*)malloc(sizeof(LNode));
int data;
scanf("%d", &data);
s->data = data;
r->next = s; //r接纳新节点
r = s; //r和s指向同个结点,相当于右移
}
r->next = NULL;
}
//删除结点
int ListDelete(LinkList &L, int i, ElemType &e)
{
if (i < 1)
return FALSE;
LNode *pre;
int j = 0;
pre = L;
while (pre != NULL && j < i - 1)
{
pre = pre->next;
j++;
}
if (pre == NULL)
return FALSE;
if (pre->next == NULL)
return FALSE;
LNode *temp = pre->next; //temp指向被删结点
e = temp->data; //返回e值
pre->next = temp->next; //被删结点前结点指向被删结点后结点
free(temp); //temp释放,原文是p,q指针,看个人习惯描述
return OK;
}
//按位查找(获取元素)
LNode* GetElem(LinkList L, int i)
{
if (i < 0)
return NULL;
LNode *p;
int j = 0;
p = L;
while (p != NULL && j < i) //j 循环到 i
{
p = p->next;
j++;
}
return p;
}
//按值查找(查找元素)
LNode* LocateElem(LinkList L, ElemType e)
{
LNode *p = L->next;
while (p != NULL && p->data != e)
p = p->next;
return p;
}
//求表的长度
int Length(LinkList L)
{
int len = 0;
LNode *p = L;
while (p->next != NULL)
{
p = p->next;
len++;
}
return len;
}
//销毁链表
int LinkListDestroy(LinkList &L)
{
if (!L)
return ERROR;
LinkList p = L;
while (p)
{
LinkList temp = p;
p = p->next;
free(temp);
temp = NULL;
}
L = NULL;
return OK;
}
//遍历*
void PrintList(LinkList &L)
{
LNode *p = L->next;
int i = 1;
while (p != NULL)
{
printf("LNode[%d] = %d\n", i, p->data);
p = p->next;
i++;
}
}
int main()
{
LinkList L;
InitList(L);
/* TailCreatList(L, 5); 创建可以用,这里是为了下面测试其他函数
PrintList(L);
HeadCreatList(L, 5);
PrintList(L); */
ListInsert(L, 1, 2);
ListInsert(L, 2, 4);
ListInsert(L, 3, 3);
ListInsert(L, 2, 5);
PrintList(L);
printf("List length = %d\n", Length(L));
int e = -1;
ListDelete(L, 2, e);
PrintList(L);
LNode* ptr = LocateElem(L, 2);
printf("List length = %d\n", Length(L));
InsertNextNode(ptr, 8);
PrintList(L);
return 0;
}
---7,24 2022更新 //这个单链表有点麻烦,后面就没那么快更新
双向链表(Double Linked List)
双向链表和比单链表多了一个Prior指针,指向前驱结点
//双向链表
typedef struct DNode{
ElemType data;
struct DNode *prior, *next;
}DNode, *DLinkList;
//初始化
int InitDLinkList(DLinkList &L)
{
L = (DNode*)malloc(sizeof(DNode));
if (L == NULL)
return FALSE;
L->prior = NULL;
L->next = NULL;
return OK;
}
//空表判断
int IsEmpty(DLinkList L)
{
if (L->next == NULL)
return TRUE;
else
return FALSE;
}
//双链表插入(p结点后插入s结点)
int InsertNextDNode(DNode *p, DNode *s)
{
if (p == NULL || s == NULL)
return FALSE;
s->next = p->next; //可以建立一个新建结点函数 来传s结点
if (p->next != NULL)
p->next->prior = s;
s->prior = p;
p->next = s;
return OK;
}
//双链表删除(指定结点)
int DeleteNextDNode(DNode *p)
{
if (p == NULL)
return FALSE;
DNode *temp = p->next;
if (temp == NULL)
return FALSE;
p->next = temp->next; //这里原文就是这么写的 p->next=q->next'
if (temp->next != NULL)
temp->next->prior = p;
free(temp);
return OK;
}
//双链表插入(非王道版)
int DListInsert(DLinkList &L, int i, ElemType e)
{
if (i < 1) //这里可以加判断i值是否合法
return FALSE;
DNode *s = (DNode*)malloc(sizeof(DNode));
DNode *pre;
int j = 0;
pre = L;
while (pre != NULL && j < i - 1)
{
pre = pre->next;
j++;
}
if (pre->next == NULL) //这一段是自己加的,初始化完只有头结点的情况
{
s->data = e;
s->next = NULL; //因为是最后一个结点 直接NULL
s->prior = pre;
pre->next = s;
}
else
{
s->data = e;
s->next = pre->next;
s->next->prior = s;
s->prior = pre;
pre->next = s;
}
}
//双链表删除(非王道版)
int DListDelete(DLinkList &L, int i, ElemType &e)
{
if (i < 1)
return FALSE;
DNode *pre;
int j = 0;
pre = L;
while (pre != NULL && j < i - 1)
{
pre = pre->next;
j++;
}
DNode *temp = pre->next; //这里要求掌握的程度到这里应该可以了
e = temp->data; //但是这个算法最后两个结点没办法删除
pre->next = pre->next->next; //从考试来看到这里就够了
pre->next->next->prior = pre; //实际应用可以再加一个被删结点后一个结点的指针
free(temp); //再加一个判断最后一个结点和只剩头结点的情况
temp = NULL; //双向链表也不算重点吧,会最关键的操作应该就可以了
} //王道没给指定位置的加和删算法
//销毁双链表
void DestoryList(DLinkList &L)
{
while (L->next != NULL)
DeleteNextDNode(L);
free(L);
L = NULL;
}
//遍历*
//前项遍历和后项遍历,按值查找和按位查找,包含头结点和不包含
//这里就写一个后项按位遍历
void PrintNext(DLinkList &L)
{
DNode* p = L->next;
int i = 1;
while (p != NULL)
{
printf("DNode[%d] = %d\n", i, p->data);
p = p->next; //前项p=p->prior; 按值if(p->data!=e);按位函数加个position i;
i++;
}
printf("\n");
}
int main()
{
DLinkList L;
InitDLinkList(L);
if (IsEmpty)
printf("DLinkList is empty.\n");
else
printf("DLinkList is not empty.\n");
DListInsert(L, 1, 1);
PrintNext(L);
DListInsert(L, 2, 3);
PrintNext(L);
DListInsert(L, 2, 4);
PrintNext(L);
DListInsert(L, 2, 5);
PrintNext(L);
DListInsert(L, 1, 6);
PrintNext(L);
int e = -1;
DListDelete(L, 1, e);
PrintNext(L);
return 0;
}
---7,26 2022更新
循环链表(Cricular Linked List)
循环链表增删查改和非循环链表大体类似
这里没有写main函数和增删查改
可以复制想要循环的单链表或双链表代码,改一些变量名称就可以运行了
静态链表:定义两个变量的结构体数组
//循环单链表
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
//初始化
int InitList(LinkList &L)
{
L = (LNode*)malloc(sizeof(LNode));
if (L == NULL)
return FALSE;
L->next = L;
return OK;
}
//空表判断
int IsEmpty(LinkList L)
{
if (L->next == L)
return TRUE;
else
return ERROR;
}
//表尾判断(结点)
int IsTail(LinkList L, LNode *p)
{
if (p->next == L)
return TRUE;
else
return FALSE;
}
//循环双链表
typedef struct DNode{
ElemType data;
struct DNode *prior, *next;
}DNode, *DLinkList;
//初始化
int InitDLinkList(DLinkList &L)
{
L = (DNode*)malloc(sizeof(DNode));
if (L == NULL)
return FALSE;
L->prior = L; //双链表这两个指针域都是指向NULL
L->next = L;
return OK;
}
//空表判断
int IsEmpty(DLinkList L)
{
if (L->next == L)
return TRUE;
else
return ERROR;
}
//表尾判断(结点)
int IsTail(DLinkList L, DNode *p)
{
if (p->next == L)
return TRUE;
else
return FALSE;
}
---7,27 2022更新
顺序表合并
顺序表合并(静态动态分配均可),这里用的是动态分配,非有序合并
La{7,5,3,11}; Lb{2,6,3}; 合并后 La{7,5,3,11,2,6,3};
//顺序表动态分配
typedef struct{
ElemType *data;
int max;
int length;
}SeqList;
//初始化
int InitSeqList(SeqList &L)
{
L.data = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE);
if (!L.data)
return OVERFLOW;
L.length = 0;
L.max = MAXSIZE;
return OK;
}
//获取元素
Status GetElem(SeqList L, int i)
{
return L.data[i - 1];
}
//查找元素
int LocateElem(SeqList L, ElemType e)
{
for (int i = 0; i <= L.length; i++)
{
if (e == L.data[i - 1])
return i - 1;
}
return ERROR;
}
//插入
int SeqlInsert(SeqList &L, int i, ElemType e)
{
if (i < 1 || i > L.length + 1)
return ERROR;
if (L.length >= L.max)
return ERROR;
for (int j = L.length; j >= i; j--)
L.data[j] = L.data[j - 1];
L.data[i - 1] = e;
L.length++;
return OK;
}
//遍历*
void PrintList(SeqList &L)
{
for (int i = 0; i < L.length; i++)
{
printf("data[%d] = %d\n", i, L.data[i]);
}
if (L.length > 0)
printf("SeqList length = %d\n", L.length);
}
//顺序表合并
void MergeList(SeqList &La, SeqList &Lb)
{
for (int i = 1; i < Lb.length + 1; i++) //判断条件,在Lb的个数下循环
{
ElemType e; //定义一个辅助元素
e = GetElem(Lb, i); //i位置的data赋值给e
if (!LocateElem(La, e)) //如果La没有这个元素
La.data[La.length++] = e; //那么就把长度+1的data赋值
}
}
int main()
{
SeqList La;
InitSeqList(La);
SeqlInsert(La, 1, 7);
SeqlInsert(La, 2, 5);
SeqlInsert(La, 3, 3);
SeqlInsert(La, 4, 11);
PrintList(La);
LocateElem(La, 2);
SeqList Lb;
InitSeqList(Lb);
SeqlInsert(Lb, 1, 2);
SeqlInsert(Lb, 2, 6);
SeqlInsert(Lb, 3, 3);
PrintList(Lb);
MergeList(La, Lb);
PrintList(La);
return 0;
}
---7, 28 2022更新
有序顺序表合并
有序表合并可搭配排序算法
La{3,5,8,11}; Lb{2,6,8,11,15,20}; 合并后 Lc{2,3,5,6,8,8,11,11,15,20};
//顺序表动态分配
typedef struct{
ElemType *data;
int max;
int length;
}SeqList;
//初始化
int InitSeqList(SeqList &L)
{
L.data = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE);
if (!L.data)
return OVERFLOW;
L.length = 0;
L.max = MAXSIZE;
return OK;
}
//插入
int SeqlInsert(SeqList &L, int i, ElemType e)
{
if (i < 1 || i > L.length + 1)
return ERROR;
if (L.length >= L.max)
return ERROR;
for (int j = L.length; j >= i; j--)
L.data[j] = L.data[j - 1];
L.data[i - 1] = e;
L.length++;
return OK;
}
//遍历*
void PrintList(SeqList &L)
{
for (int i = 0; i < L.length; i++)
{
printf("data[%d] = %d\n", i, L.data[i]);
}
if (L.length > 0)
printf("SeqList length = %d\n", L.length);
}
//有序顺序表合并(排序算法后应用场景)
void MergeSeqList(SeqList &La, SeqList &Lb, SeqList &Lc)
{
Lc.length = La.length + Lb.length; //将A和B的长度加起来给到新表
ElemType *pa = La.data, *pa_last = pa + La.length - 1; //指针指向第一个元素和最后一个元素
ElemType *pb = Lb.data, *pb_last = pb + Lb.length - 1;
ElemType *pc = Lc.data; //pc指针指向新表头个地址
while (pa <= pa_last && pb <= pb_last) //这个判定条件是地址大小,顺序表是连续空间
{
if (*pa < *pb) //如果pa(La)内的数值小于pb(Lb)
*(pc++) = *(pa++); //把pa(小的那个)赋值给新表pc
else
*(pc++) = *(pb++);
} //这两个判断也是上面if判断
while (pa <= pa_last) //跳出循环必有一个表空了,两个判断
*(pc++) = *(pa++); //这里是pa还有值(pb空了),剩下的给pc
while (pb <= pb_last)
*(pc++) = *(pb++);
}
int main()
{
SeqList La;
InitSeqList(La);
SeqlInsert(La, 1, 3);
SeqlInsert(La, 2, 5);
SeqlInsert(La, 3, 8);
SeqlInsert(La, 4, 11);
PrintList(La);
SeqList Lb;
InitSeqList(Lb);
SeqlInsert(Lb, 1, 2);
SeqlInsert(Lb, 2, 6);
SeqlInsert(Lb, 3, 8);
SeqlInsert(Lb, 4, 11);
SeqlInsert(Lb, 5, 15);
SeqlInsert(Lb, 6, 20);
PrintList(Lb);
SeqList Lc;
InitSeqList(Lc);
MergeSeqList(La, Lb, Lc);
PrintList(Lc);
return 0;
}
有序链表合并
La{3,5,8,11}; Lb{2,6,8,11,15,20}; 合并后 Lc{2,3,5,6,8,8,11,11,15,20};
//单链表
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
//初始化带头结点单链表
int InitList(LinkList &L)
{
L = (LNode*)malloc(sizeof(LNode));
if (L == NULL) //内存不足的情况
return FALSE;
L->next = NULL; //头结点指向NULL
return OK;
}
//按位插入
int ListInsert(LinkList &L, int i, ElemType e)
{
if (i < 1)
return FALSE;
LNode *pre; // Previous 指针 指向插入前一个结点
int j = 0;
pre = L; //L 头结点
while (pre != NULL && j < i - 1) //pre找到了i前一个结点
{
pre = pre->next; //从第一个开始找 找不到就下一个结点
j++;
}
if (pre == NULL)
return FALSE;
LNode *s = (LNode*)malloc(sizeof(LNode)); //找到了,新建一个结点
s->data = e; //1.先将插入结点赋值
s->next = pre->next; //2.将i前一个结点的next指针赋值给插入结点
pre->next = s; //3.把i前一个结点指向新建结点
return OK;
}
//头插法建立链表(非王道版)
void HeadCreatList(LinkList L, int n)
{
printf("Please input %d numbers and Separate with SPACE\n", n);
for (int i = 0; i < n; i++)
{ //这里是手动键盘输入数据
LNode *p = (LNode*)malloc(sizeof(LNode));
int data;
scanf("%d", &data);
p->data = data;
p->next = L->next;
L->next = p;
}
}
//尾插法建立链表(非王道版,王道版是头结点建立包含在里面)
void TailCreatList(LinkList L, int n)
{
printf("Please input %d numbers and Separate with SPACE\n", n);
LNode *s, *r;
r = L; //定义个指针指向头结点,此时头结点是终端结点
for (int i = 0; i < n; i++)
{
LNode *s = (LNode*)malloc(sizeof(LNode));
int data;
scanf("%d", &data);
s->data = data;
r->next = s; //r接纳新节点
r = s; //r和s指向同个结点,相当于右移
}
r->next = NULL;
}
//求表的长度
int Length(LinkList L)
{
int len = 0;
LNode *p = L;
while (p->next != NULL)
{
p = p->next;
len++;
}
return len;
}
//遍历*
void PrintList(LinkList &L)
{
LNode *p = L->next;
int i = 1;
while (p != NULL)
{
printf("LNode[%d] = %d\n", i, p->data);
p = p->next;
i++;
}
}
//有序链表合并
void MergeLinkList(LinkList &La, LinkList &Lb, LinkList &Lc)
{ //C语言&变成*
Lc = La; //新链表指向La,C语言写法 *La = *La;
LNode *pa = La->next, *pb = Lb->next; //两个辅助指针指向第一个结点,C语言写法 LNode *pa = *(La)->next;
LNode *pc = Lc;
while (pa && pb) //当其中一个表还有数值时循环
{
if (pa->data < pb->data) //如果pa(La)内的指小于pb(Lb)
{
pc->next = pa; //pc指向pa(小的)
pc = pa; //pa的地址给到pc
pa = pa->next; //pa移到下一个
}
else
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
pc->next = pa ? pa : pb; //其中一个表没有数据了,判断哪个还有,接给pc
free(Lb);
La = Lb = NULL;
}
int main()
{
LinkList La, Lb, Lc;
InitList(La);
InitList(Lb);
InitList(Lc);
ListInsert(La, 1, 3); //可以用头插尾插法建立,手动数值更方便
ListInsert(La, 2, 5); //void HeadCreatList(LinkList L, int n)
ListInsert(La, 3, 8);
ListInsert(La, 4, 11);
ListInsert(Lb, 1, 2);
ListInsert(Lb, 2, 6);
ListInsert(Lb, 3, 8);
ListInsert(Lb, 4, 11);
ListInsert(Lb, 5, 15);
ListInsert(Lb, 6, 20);
PrintList(La);
printf("LaLinkList length = %d\n", Length(La));
PrintList(Lb);
printf("LbLinkList length = %d\n", Length(Lb));
PrintList(Lc);
printf("LcLinkList length = %d\n", Length(Lc));
MergeLinkList(La, Lb, Lc);
PrintList(Lc);
printf("LcLinkList length = %d\n", Length(Lc));
return 0;
}
---7,30 2022更新 //昨天忘发了,第二章完结
顺序栈(Sequence Stack)
栈这个我分了两个版本,王道版和严蔚敏版,区别是王道版top指针指向最上面的元素,而严蔚敏版top指针指向最上面元素的上面一个元素,我更习惯用严蔚敏版
举个例子,我这里有5个空间,a[0]~a[4],设a[0]、a[1]内均有元素,那么王道版的top指针是指向a[1],而严蔚敏版是指向a[2]
这样好理解吧,那么如果我要存a[4]这个元素严蔚敏版能存吗,答案是可以的,只要S.top-S.base != S.stacksize;里面没满就可以存元素
这两个版本就是定义S.top指针不一样,而这个差异会导致压栈和出栈完全不同,看你习惯用哪个就用哪个,顺序栈我分两个版本,链栈,队列都是严蔚敏版,栈和队列和链表都是重点,会写出完整代码会更好理解栈和队列,但基础还是顺序表和链表,他们都是这两种构成,不过是栈只能后进先出(LIFO/一端),队列只能先进先出(FIFO/一端),双端队列则不受限制
王道版
//顺序栈
typedef struct{
ElemType data[MAXSIZE];
int top;
}SqStack;
//初始化
void InitStack(SqStack &S)
{
S.top = -1;
}
//判断栈空
int IsEmpty(SqStack S)
{
if (S.top == -1)
return TRUE;
else
return FALSE;
}
//入栈
int Push(SqStack &S, ElemType x)
{
if (S.top == MAXSIZE - 1)
return FALSE;
S.top = S.top + 1;
S.data[S.top] = x;
// S.data[++S.top] = x;
return OK;
}
//出栈
int Pop(SqStack &S, ElemType &x)
{
if (S.top == -1)
return FALSE;
x = S.data[S.top];
S.top = S.top - 1; //S.data[S.top--] = x;
return TRUE;
}
//读栈顶元素
int GetTop(SqStack S, ElemType &x)
{
if (S.top == -1)
return FALSE;
x = S.data[S.top];
return x;
}
/*
//共享栈
typedef struct{
ElemType data[MAXSIZE];
int top0;
int top1;
}
//初始化
void InitStack(ShStack &S)
{
S.top0 = -1;
S.top1 = MAXSIZE;
}
//判断栈满条件 top0 + 1 == top1;
*/
//遍历*
void PrintStack(SqStack S)
{
for (int i = 0; i < S.top + 1; i++)
{
printf("Stack[%d] = %d\n", i, S.data[i]);
}
printf("\n");
}
int main()
{
SqStack S;
InitStack(S);
Push(S, 1);
Push(S, 2);
Push(S, 3);
PrintStack(S);
ElemType e = 0;
printf("GetTop = %d\n", GetTop(S, e));
while (!IsEmpty(S)) //出完所有栈内元素
{
ElemType e = -1;
Pop(S, e);
printf("Stack[%d] = %d\n", S.top + 1, e);
}
return 0;
}
严蔚敏版
//顺序栈
typedef struct{
ElemType *base; //栈底指针
ElemType *top; //栈顶指针
int stacksize;
}SqStack;
//初始化
int InitStack(SqStack &S)
{
S.base = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE);
if (!S.base)
exit(OVERFLOW);
S.top = S.base;
S.stacksize = MAXSIZE;
return OK;
}
//入栈
int Push(SqStack &S, ElemType e)
{
if (S.top - S.base == S.stacksize)
return ERROR;
*S.top++ = e;
return OK;
}
//出栈
int Pop(SqStack &S, ElemType &e)
{
if (S.top == S.base)
return ERROR;
e = *--S.top;
return OK;
}
//取栈顶元素
ElemType GetTop(SqStack S)
{
if (S.top != S.base)
return *(S.top - 1);
}
//判断栈空
int IsEmpty(SqStack &S)
{
if (S.base == S.top)
return TRUE;
else
return FALSE;
}
//判断栈满
int IsFull(SqStack &S)
{
if (S.top - S.base == S.stacksize)
return TRUE;
else
return FALSE;
}
//遍历*
void PrintStack(SqStack S)
{
int *p, *q;
p = S.base, q = S.top; //这个是从低到高,也就是从栈底到栈顶
int i = 0; //也可以改成栈顶到栈底遍历
while (p != q) //q--,i=S.top-1,就从栈顶遍历,看个人
{
printf("Stack[%d] = %d\n", i, *p);
p++, i++;
}
}
int main()
{
SqStack S;
InitStack(S);
Push(S, 1);
Push(S, 2);
Push(S, 3);
PrintStack(S);
ElemType e = 0;
printf("GetTop = %d\n", GetTop(S));
int *q = S.top - 1;
while (!IsEmpty(S)) //出完所有栈内元素
{
ElemType e = -1;
Pop(S, e);
printf("Stack[%d] = %d\n", *q, e);
q