前言
- 本文中使用数据类型时,若无特殊需求,节点数据默认都采用
int
类型。
线性表
顺序表
定义
//静态定义
#define MaxSize 50
typedef struct{
int data[MaxSize];//采用数组的形式定义
int length; //表示顺序表的长度
}seqList;
//动态定义
#define InitSize 50
typedef struct{
int * data; //采用指针的形式定义
int MaxSize,length; //顺序表的最大长度以及当前顺序表的长度
}seqList;
插入
/*数组定义的形式*/
/**
* 按照指定位置插入元素
* &L 顺序表
* i 插入的位置(合法的位置为 1 <= i <= length+1)
* e 待插入的元素
*/
bool insertList(seqList & L, int i, int e) {
if (i < 1 || i > L.length + 1)
return false; //插入位置不合法
if (L.length >= MaxSize) //顺序表当前长度等于最大长度
return false; //顺序表空间已满
for (int j = L.length; j >= i; j--) { //将第i个元素及以后的元素依次向后移动
L.data[j] = L.data[j - 1];
}
L.data[i - 1] = e;//插入元素
L.length++;//顺序表长度加一
return true;
}
删除
/*数组定义的形式*/
/**
* 按照指定位置删除元素
* &L 顺序表
* i 删除的位置(合法的位置为 1 <= i <= length)
* e 删除的元素
*/
bool deleteList(seqList & L, int i, int & e) {
if (i < 1 || i > L.length) //位置不合法
return false;
e = L.data[i - 1]; //将被删除的元素赋值给e,以便删除结束后知道删除的元素
for (int j = i; j < L.length; j++) { //开始删除
L.data[j - 1] = L.data[j]; //待删除元素的后一个元素依次覆盖前一个元素
}
L.length--;
return true;
}
查找元素
/*数组定义的形式*/
/**
* 采用遍历的方式查找
* &L 顺序表
* e 查找的元素
*/
int findList(seqList & L, int e) {
for (int i = 0; i < L.length; i++) {
if (L.data[i] == e)
return i + 1; //返回的是元素位置
}
return 0; //未找到元素,返回0
}
链表
定义
//单链表定义
typedef struct LNode {
int data;//节点数据
struct LNode *next;//下一个节点指针
} LNode, *LinkList;
创建单链表
带头结点的方式
采用带头结点的方式创建链表(头插法)
//采用带头结点的方式创建链表(头插法)
void createListForHead(LinkList &L) {
LNode *s;//待插入的节点
int e;//待插入的元素
L = (LinkList)malloc(sizeof(LNode));//为链表分配空间
L->next = NULL;//初始化为空
while (true) {
printf("请输入当前要插入的元素数据:");
scanf("%d", &e);//输入待插入的元素
if (e == -1)//循环退出条件
break;
s = (LNode * )malloc(sizeof(LNode));//为待插入节点分配空间
s->data = e;//将输入的元素赋值到节点的数据域
s->next = L->next;//修改指针指向(新节点的下一个节点指针指向头结点的下一个节点指针)
L->next = s;//修改指针指向(头结点的下一个节点指针指向新的节点)
}
}
采用带头结点的方式创建链表(尾插法)
//采用带头结点的方式创建链表(尾插法)
void createListForRear(LinkList &L) {
LNode *s, *r; //待插入的节点和尾指针
int e;//待插入的元素
L = (LinkList)malloc(sizeof(LNode));//为链表分配空间
r = L;//初始时,尾指针指向头结点
while (true) {
printf("请输入当前要插入的元素数据:");
scanf("%d", &e);//输入待插入的元素
if (e == -1)//循环退出条件
break;
s = (LNode *)malloc(sizeof(LNode));//为待插入节点分配空间
s->data = e;//将输入的元素赋值到节点的数据域
r->next = s;//尾指针的下一个节点指向待插入元素
r = s;//修改尾指针指向(指向新节点)
}
r->next = NULL;//将尾指针的下一个节点置空,表示当前即为最后一个元素
}
查找节点
按位置查找节点
//按位置查找节点
LNode * getNodeByLocate(LinkList &L, int i) {
if (i == 0)
return L;//返回头结点
if (i < 1)
return NULL;//位置非法,返回空
LNode *p = L->next;//p指向第一个节点
int j = 1;//设置计数从1开始
while (p && j < i) {//从1开始找,p不为NULL时说明有元素,j<i说明还未到要找到的元素位置
p = p->next;//指向下一个元素
j++;//计数加一
}
return p;//若找到,返回的就是该节点;若未找到就会返回NULL
}
按值查找节点
//按值查找节点
LNode * getNodeByElem(LinkList &L, int e) {
LNode *p = L->next;//p指向第一个节点
while (p && p->data != e) {//从第一个节点开始找。判断当前节点的数据是否与待查找数据一致
p = p->next;//不一致时,指针下移。指针移到最后时,p就是NULL
}
return p;//返回找到的节点。如果未找到,p指向的就是NULL
}
插入节点
给定位置插入节点
//插入节点(给定位置插入节点)
/*
* 注意:以下代码为核心部分,未进行插入位置合法性校验
* &L 插入的链表地址
* i 插入的位置
* *s 插入的节点
*/
void insertLNodeByLocate(LinkList &L, int i, LNode *s) {
LNode *p = getNodeByLocate(L, i - 1); //查找待插入位置的前一个节点
s->next = p->next;
p->next = s;
}
给定节点p之前插入一个节点s
//插入节点(给定节点p之前插入一个节点s)
/*
* 注意:以下代码为核心部分,未进行插入位置合法性校验
* *p 给定节点
* *s 插入的节点
*/
void insertLNodeByNode(LNode *p, LNode *s) {
//交换数据
int temp = p->data;
p->data = s->data;
s->data = temp;
//修改指针
s->next = p->next;
p->next = s;
}
删除
删除给定位置的节点
//删除给定位置的节点
bool removeLNodeByLocate(LinkList &L, int i) {
LNode *p = getNodeByLocate(L, i - 1); //查找待删除节点的前一个结点
LNode *q = p->next;//指向待删除节点
p->next = q->next;//修改指针
free(q);//释放指针
return true;
}
删除指定节点
//删除指定节点
/*
* 示意过程
* 1->2->(3)->4->5->NULL(原始链表)删除3号节点
* 1->2->(4)->4->5->NULL(复制3号节点下一个节点的数据到三号节点)
* 1->2->(4)->5->NULL(删除3号节点的下一个结点,就相当于形式上删除了3号节点)
*/
bool removeLNodeByNode(LNode *p) {
LNode *q = p->next;//指定节点的下一个结点
p->data = q->data;//将下一个节点的数据复制到待删除节点,然后将下一个结点删除即可
p->next = q->next;//修改节点指向
free(q);
return true;
}
双链表
定义
//双链表定义
typedef struct DNode{
int data;//节点数据
struct DNode *prior,*next;//指向前一个节点的指针和指向后一个结点的指针
}DNode,*DLinkList;
插入
将节点s插入到结点p之后
/**
* @brief 双链表插入数据(将节点s插入到结点p之后)
*
* @param p 给定节点
* @param s 待插入节点
*
* @return 插入是否成功
**/
bool insertDNode(DNode *p, DNode *s) {
if (p->next == NULL) { //插入节点为最后一个结点
p->next = s;
s->prior = p;
s->next = NULL;
} else {
s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
}
return true;
}
删除
删除所给节点的后一个节点
/**
* @brief 删除所给节点的后一个节点
*
* @param p 所给节点
*
* @return 删除结果
**/
bool removeDNode(DNode *p) {
DNode *q = p->next;
if (q != NULL) {
free(q);
q->next->prior = p;
p->next = q->next;
free(q);
}
return true;
}
链表代码汇总
#include <stdio.h>
#include <stdlib.h>
//单链表定义
typedef struct LNode {
int data;//节点数据
struct LNode *next;//下一个节点指针
} LNode, *LinkList;
//双链表定义
typedef struct DNode {
int data;//节点数据
struct DNode *prior, *next; //指向前一个节点的指针和指向后一个结点的指针
} DNode, *DLinkList;
//采用带头结点的方式创建链表(头插法)
void createListForHead(LinkList &L) {
LNode *s;//待插入的节点
int e;//待插入的元素
L = (LinkList)malloc(sizeof(LNode));//为链表分配空间
L->next = NULL;//初始化为空
while (true) {
printf("请输入当前要插入的元素数据:");
scanf("%d", &e);//输入待插入的元素
if (e == -1)//循环退出条件
break;
s = (LNode * )malloc(sizeof(LNode));//为待插入节点分配空间
s->data = e;//将输入的元素赋值到节点的数据域
s->next = L->next;//修改指针指向(新节点的下一个节点指针指向头结点的下一个节点指针)
L->next = s;//修改指针指向(头结点的下一个节点指针指向新的节点)
}
}
//采用带头结点的方式创建链表(尾插法)
void createListForRear(LinkList &L) {
LNode *s, *r; //待插入的节点和尾指针
int e;//待插入的元素
L = (LinkList)malloc(sizeof(LNode));//为链表分配空间
r = L;//初始时,尾指针指向头结点
while (true) {
printf("请输入当前要插入的元素数据:");
scanf("%d", &e);//输入待插入的元素
if (e == -1)//循环退出条件
break;
s = (LNode *)malloc(sizeof(LNode));//为待插入节点分配空间
s->data = e;//将输入的元素赋值到节点的数据域
r->next = s;//尾指针的下一个节点指向待插入元素
r = s;//修改尾指针指向(指向新节点)
}
r->next = NULL;//将尾指针的下一个节点置空,表示当前即为最后一个元素
}
//按位置查找节点
LNode * getNodeByLocate(LinkList &L, int i) {
if (i == 0)
return L;//返回头结点
if (i < 1)
return NULL;//位置非法,返回空
LNode *p = L->next;//p指向第一个节点
int j = 1;//设置计数从1开始
while (p && j < i) {//从1开始找,p不为NULL时说明有元素,j<i说明还未到要找到的元素位置
p = p->next;//指向下一个元素
j++;//计数加一
}
return p;//若找到,返回的就是该节点;若未找到就会返回NULL
}
//按值查找节点
LNode * getNodeByElem(LinkList &L, int e) {
LNode *p = L->next;//p指向第一个节点
while (p && p->data != e) {//从第一个节点开始找。判断当前节点的数据是否与待查找数据一致
p = p->next;//不一致时,指针下移。指针移到最后时,p就是NULL
}
return p;//返回找到的节点。如果未找到,p指向的就是NULL
}
//插入节点(给定位置插入节点)
/*
* &L 插入的链表地址
* i 插入的位置
* *s 插入的节点
*/
bool insertLNodeByLocate(LinkList &L, int i, LNode *s) {
LNode *p = getNodeByLocate(L, i - 1); //查找待插入位置的前一个节点
s->next = p->next;
p->next = s;
return true;
}
//插入节点(给定节点p之前插入一个节点s)
/*
* *p 给定节点
* *s 插入的节点
*/
bool insertLNodeByNode(LNode *p, LNode *s) {
//交换数据
int temp = p->data;
p->data = s->data;
s->data = temp;
//修改指针
s->next = p->next;
p->next = s;
return true;
}
//删除给定位置的节点
bool removeLNodeByLocate(LinkList &L, int i) {
LNode *p = getNodeByLocate(L, i - 1); //查找待删除节点的前一个结点
LNode *q = p->next;//指向待删除节点
p->next = q->next;//修改指针
free(q);//释放指针
return true;
}
//删除指定节点
/*
* 示意过程
* 1->2->(3)->4->5->NULL(原始链表)删除3号节点
* 1->2->(4)->4->5->NULL(复制3号节点下一个节点的数据到三号节点)
* 1->2->(4)->5->NULL(删除3号节点的下一个结点,就相当于形式上删除了3号节点)
*/
bool removeLNodeByNode(LNode *p) {
LNode *q = p->next;//指定节点的下一个结点
p->data = q->data;//将下一个节点的数据复制到待删除节点,然后将下一个结点删除即可
p->next = q->next;//修改节点指向
free(q);
return true;
}
//获取单链表长度
int getListLength(LinkList &L) {
LNode *p = L->next;
int count = 0;
while (p) {
count++;
p = p->next;
}
return count;
}
//输出单链表元素
void showList(LinkList L) {
LNode *p = L->next;
while (p) {
if (p->next) {//有下一个节点时,就输出箭头
printf("%d -> ", p->data);
} else {
printf("%d\n", p->data);
}
p = p->next;
}
}
//创建带测试数据的单链表(尾插法)
void createListForRearWithTestData(LinkList &L) {
LNode *s, *r; //待插入的节点和尾指针
// int data[] = {5, 3, 1, 2, 4, 6, 9, 7, 8, 10}; //待插入的元素(无序)
int data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //待插入的元素(有序)
L = (LinkList)malloc(sizeof(LNode));//为链表分配空间
r = L;//初始时,尾指针指向头结点
int len = sizeof(data) / sizeof(int);//数组元素长度
for (int i = 0; i < len; i++) {
s = (LNode *)malloc(sizeof(LNode));//为待插入节点分配空间
s->data = data[i];//将输入的元素赋值到节点的数据域
r->next = s;//尾指针的下一个节点指向待插入元素
r = s;//修改尾指针指向(指向新节点)
}
r->next = NULL;//将尾指针的下一个节点置空,表示当前即为最后一个元素
}
//双链表创建并初始数据
void createDLinkList(DLinkList &DL) {
// int data[] = {5, 3, 1, 2, 4, 6, 9, 7, 8, 10}; //待插入的元素(无序)
int data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //待插入的元素(有序)
DL = (DNode *)malloc(sizeof(DNode));
DL->prior = NULL;
DL->next = NULL;
int len = sizeof(data) / sizeof(int);//数组元素长度
// DNode *p = s->next;
DNode *s;
for (int i = 0; i < len; i++) {
s = (DNode *)malloc(sizeof(DNode));
s->data = data[i];
if (DL->next == NULL) {
DL->next = s;
s->prior = DL;
s->next = NULL;
} else {
s->next = DL->next;
DL->next->prior = s;
s->prior = DL;
DL->next = s;
}
}
}
//显示双链表中的数据
void showDLinkList(DLinkList &DL) {
DNode *p = DL->next;
while (p) {
if (p->next) {
printf("%d <=> ", p->data);
} else {
printf("%d\n", p->data);
}
p = p->next;
}
}
/**
* @brief 双链表插入数据(将节点s插入到结点p之后)
*
* @param p 给定节点
* @param s 待插入节点
*
* @return 插入是否成功
**/
bool insertDNode(DNode *p, DNode *s) {
if (p->next == NULL) { //插入节点为最后一个结点
p->next = s;
s->prior = p;
s->next = NULL;
} else {
s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
}
return true;
}
/**
* @brief 删除所给节点的后一个节点
*
* @param p 所给节点
*
* @return 删除结果
**/
bool removeDNode(DNode *p) {
DNode *q = p->next;
if (q != NULL) {
free(q);
q->next->prior = p;
p->next = q->next;
free(q);
}
return true;
}
int main() {
/*
LinkList L ;
// createListForHead(L);
// createListForRear(L);
createListForRearWithTestData(L);
printf("当前链表中节点信息为:\n");
showList(L);
printf("链表长度为:%d\n", getListLength(L));
// LNode * node = getNodeByLocate(L, 10);
// printf("找到的元素为:节点地址:%p,节点元素:%d\n", node, node->data);
// printf("*****************华丽的分割线*****************\n");
// LNode * node2 = getNodeByElem(L, 50);
// printf("找到的元素为:节点地址:%p,节点元素:%d\n", node2, node2->data);
// printf("*****************华丽的分割线*****************\n");
// LNode *s = (LNode *)malloc(sizeof(LNode));
// s->data = 666;
// insertLNodeByLocate(L, 3, s);
// printf("在3号位置插入节点后,链表中节点信息为:\n");
// showList(L);
// printf("链表长度为:%d\n", getListLength(L));
printf("*****************华丽的分割线*****************\n");
// LNode *p = getNodeByLocate(L, 3); //查找一个节点
// LNode *s = (LNode *)malloc(sizeof(LNode));
// s->data = 666;
// insertLNodeByNode(p, s);
// printf("在3号节点前插入节点后,链表中节点信息为:\n");
// removeLNodeByLocate(L, 3);
LNode *p = getNodeByLocate(L, 3); //查找一个节点
removeLNodeByNode(p);
printf("删除3号节点后链表信息为:\n");
showList(L);
printf("链表长度为:%d\n", getListLength(L));
*/
DLinkList DL;
createDLinkList(DL);
showDLinkList(DL);
DNode *p = DL->next->next->next;
// printf("%d节点前一个结点为:%d", p->data, p->prior->data);
// DNode *s = (DNode *) malloc(sizeof(DNode));
// s->data = 666;
// insertDNode(p, s);
// printf("插入节点后,双链表信息为:\n");
// showDLinkList(DL);
// printf("新插入的节点前一个结点数据为:%d", s->prior->data);
removeDNode(p);
showDLinkList(DL);
return 0;
}
栈和队列
顺序栈
定义
//顺序栈的最大容量
#define MaxSize 50
//顺序栈定义
typedef struct {
int data[MaxSize];//存放栈中的元素
int top;//栈顶指针
} SeqStack;
初始化栈
//初始化栈
void InitSeqStack(SeqStack &S) {
S.top = 0;//栈顶指针指向0。若栈顶指针指向-1,后续操作需要做出相应的调整
}
栈判空
//判断栈是否为空
bool emptySeqStack(SeqStack &S) {
return S.top == 0;//等于0即为空
}
进栈
/**
* @brief 进栈
*
* @param S 顺序栈
* @param e 待进栈元素
*
* @return 操作结果
**/
bool pushSeqStack(SeqStack &S, int e) {
if (S.top == MaxSize)//栈满
return false;
S.data[S.top++] = e;//将待进栈的元素添加到栈中就,并修改栈顶指针
return true;
}
出栈
/**
* @brief 出栈
*
* @param S 顺序栈
*
* @return 出栈元素
**/
int popSeqStack(SeqStack &S) {
if (emptySeqStack(S))
return -1;
return S.data[--S.top];//取出栈顶元素,并修改栈顶指针
}
获取栈顶元素
//获取栈顶元素
int getTop(SeqStack &S) {
int _top = S.top;//记录当前栈顶指针,避免在后面操作修改到栈顶指针
return S.data[_top - 1];
}
顺序栈代码汇总
#include <stdio.h>
#include <stdlib.h>
//顺序栈的最大容量
#define MaxSize 50
//顺序栈定义
typedef struct {
int data[MaxSize];//存放栈中的元素
int top;//栈顶指针
} SeqStack;
//初始化栈
void InitSeqStack(SeqStack &S) {
S.top = 0;//栈顶指针指向0。若栈顶指针指向-1,后续操作需要做出相应的调整
}
//判断栈是否为空
bool emptySeqStack(SeqStack &S) {
return S.top == 0;//等于0即为空
}
/**
* @brief 进栈
*
* @param S 顺序栈
* @param e 待进栈元素
*
* @return 操作结果
**/
bool pushSeqStack(SeqStack &S, int e) {
if (S.top == MaxSize)//栈满
return false;
S.data[S.top++] = e;//将待进栈的元素添加到栈中就,并修改栈顶指针
return true;
}
/**
* @brief 出栈
*
* @param S 顺序栈
*
* @return 出栈元素
**/
int popSeqStack(SeqStack &S) {
if (emptySeqStack(S))
return -1;
return S.data[--S.top];//取出栈顶元素,并修改栈顶指针
}
//获取栈顶元素
int getTop(SeqStack &S) {
int _top = S.top;//记录当前栈顶指针,避免在后面操作修改到栈顶指针
return S.data[_top - 1];
}
//显示栈中元素
void showSeqStack(SeqStack &S) {
for (int i = S.top - 1; i >= 0; i--) {
if (i == S.top - 1) {
printf(" |----------|\n");
}
printf(" | %3d |\n", S.data[i]);
printf(" |----------|\n");
}
}
int main() {
SeqStack S;
InitSeqStack(S);
for (int i = 1; i <= 10; i++) {
pushSeqStack(S, i);
}
showSeqStack(S);
for (int i = 0; i < 5; i++) {
printf("当前栈顶元素为:%d\n", popSeqStack(S));
}
printf("<=====出栈后,栈中信息=====>\n");
showSeqStack(S);
printf("当前栈顶元素为:%d\n", getTop(S));
showSeqStack(S);
return 0;
}
链栈
定义
//链栈节点定义
typedef struct SNode {
int data;//数据元素
struct SNode *next;//下一个节点指针
} SNode;
//链栈定义
typedef struct {
SNode *top;//栈顶指针
}*LinkStack;
初始化
//初始化栈
void initStack(LinkStack &LS) {
LS = (LinkStack)malloc(sizeof(LinkStack));//分配空间
LS->top = NULL;//初始化时,栈顶指针指向空
}
进栈
/**
* @brief 进栈(类似于单链表的头插法)
*
* @param LS 链栈
* @param e 待进栈元素
**/
void pushStack(LinkStack &LS, int e) {
SNode *s = (SNode *)malloc(sizeof(SNode));//为节点分配一个空间
s->data = e;//将数据赋值到节点里
s->next = LS->top;//新节点的下一个指向为栈顶指针的下一个指向
LS->top = s;//将栈顶指针指向新的节点
}
出栈
/**
* @brief 出栈
*
* @param LS 链栈
*
* @return 栈顶元素
**/
int popStack(LinkStack &LS) {
SNode *p = LS->top;//记录栈顶指针
if (p == NULL) {//空栈时返回-1
return -1;
}
int e = p->data;//记录栈顶元素
SNode *q = p->next;//记录栈顶指针的下一个节点
LS->top = q;//修改栈顶指针
free(p);//释放空间
return e;//返回栈顶元素
}
链栈代码汇总
#include <stdio.h>
#include <stdlib.h>
//链栈节点定义
typedef struct SNode {
int data;//数据元素
struct SNode *next;//下一个节点指针
} SNode;
//链栈定义
typedef struct {
SNode *top;//栈顶指针
}*LinkStack;
//初始化栈
void initStack(LinkStack &LS) {
LS = (LinkStack)malloc(sizeof(LinkStack));//分配空间
LS->top = NULL;//初始化时,栈顶指针指向空
}
/**
* @brief 进栈(类似于单链表的头插法)
*
* @param LS 链栈
* @param e 待进栈元素
**/
void pushStack(LinkStack &LS, int e) {
SNode *s = (SNode *)malloc(sizeof(SNode));//为节点分配一个空间
s->data = e;//将数据赋值到节点里
s->next = LS->top;//新节点的下一个指向为栈顶指针的下一个指向
LS->top = s;//将栈顶指针指向新的节点
}
/**
* @brief 出栈
*
* @param LS 链栈
*
* @return 栈顶元素
**/
int popStack(LinkStack &LS) {
SNode *p = LS->top;//记录栈顶指针
if (p == NULL) {//空栈时返回-1
return -1;
}
int e = p->data;//记录栈顶元素
SNode *q = p->next;//记录栈顶指针的下一个节点
LS->top = q;//修改栈顶指针
free(p);//释放空间
return e;//返回栈顶元素
}
void showStack(LinkStack &LS) {
SNode *p = LS->top;
while (p != NULL) {
if (p->next) {
printf("%d -> ", p->data);
} else {
printf("%d\n", p->data);
}
p = p->next;
}
}
int main() {
LinkStack LS;
initStack(LS);
for (int i = 1; i <= 10; i++) {
pushStack(LS, i);
}
showStack(LS);
printf("出栈元素为:%d\n", popStack(LS));
showStack(LS);
return 0;
}
循环队列
定义
//定义队列最大个数(采用循环队列时,需要牺牲一个空间来方便处理队满的情况)
#define MaxSize 11
//定义队列
typedef struct {
int data[MaxSize];//存放队列数据
int front, rear; //队头、队尾指针
} SeqQueue;
初始化
//初始化
void initQueue(SeqQueue &Q) {
Q.front = 0;
Q.rear = 0;
}
判空
//队空判断
bool emptyQueue(SeqQueue &Q) {
return Q.front == Q.rear;//队头与队尾指向通一个地方时,队为空
}
判满
//队满判断(采用的时牺牲一个空间的方式来判断)
bool fullQueue(SeqQueue &Q) {
return (Q.rear + 1) % MaxSize == Q.front;
}
入队
//入队
bool enQueue(SeqQueue &Q, int e) {
if (fullQueue(Q)) //栈满时,返回false
return false;
Q.data[Q.rear] = e;//在队尾插入元素
Q.rear = (Q.rear + 1) % MaxSize; //计算队尾指针
return true;
}
出队
//出队
int deQueue(SeqQueue &Q) {
if (emptyQueue(Q)) //队空时,返回-1
return -1;
int e = Q.data[Q.front];//出队元素
Q.front = (Q.front + 1) % MaxSize; //计算队头指针
return e;
}
循环队列代码汇总
#include <stdio.h>
#include <stdlib.h>
//定义队列最大个数(采用循环队列时,需要牺牲一个空间来方便处理队满的情况)
#define MaxSize 11
//定义队列
typedef struct {
int data[MaxSize];//存放队列数据
int front, rear; //队头、队尾指针
} SeqQueue;
//初始化
void initQueue(SeqQueue &Q) {
Q.front = 0;
Q.rear = 0;
}
//队空判断
bool emptyQueue(SeqQueue &Q) {
return Q.front == Q.rear;//队头与队尾指向通一个地方时,队为空
}
//队满判断(采用的时牺牲一个空间的方式来判断)
bool fullQueue(SeqQueue &Q) {
return (Q.rear + 1) % MaxSize == Q.front;
}
//入队
bool enQueue(SeqQueue &Q, int e) {
if (fullQueue(Q)) //栈满时,返回false
return false;
Q.data[Q.rear] = e;//在队尾插入元素
Q.rear = (Q.rear + 1) % MaxSize; //计算队尾指针
return true;
}
//出队
int deQueue(SeqQueue &Q) {
if (emptyQueue(Q)) //队空时,返回-1
return -1;
int e = Q.data[Q.front];//出队元素
Q.front = (Q.front + 1) % MaxSize; //计算队头指针
return e;
}
//显示队列元素
void showQueue(SeqQueue Q) {
while (Q.front != Q.rear) {
if (Q.front + 1 == Q.rear)
printf("%d\n", Q.data[Q.front]);
else
printf("%d <- ", Q.data[Q.front]);
Q.front = (Q.front + 1) % MaxSize;
}
}
int main() {
SeqQueue Q;
initQueue(Q);
printf("入队10个元素\n");
for (int i = 1; i <= 10; i++) {
enQueue(Q, i);
}
showQueue(Q);
printf("出队5个元素\n");
for (int i = 0; i < 5; i++) {
deQueue(Q);
}
showQueue(Q);
printf("再入队10个元素\n");
for (int i = 1; i <= 10; i++) {
enQueue(Q, i + 10);//队列满了后的元素不会入队
}
showQueue(Q);
return 0;
}
链队
定义
//定义链队列节点
typedef struct LQNode {
int data;//节点数据
struct LQNode *next;//下一个节点指针
} LQNode;
//定义链队列
typedef struct {
LQNode *front, *rear; //队头,队尾指针
} LinkQueue;
初始化
//初始化链队列
void initQueue(LinkQueue &LQ) {
LQ.front = LQ.rear = (LQNode *)malloc(sizeof(LQNode));//队头与队尾指针都先指向同一个节点
LQ.front->next = NULL;//队头的下一个节点指向空
}
判空
//判断队空
bool emptyQueue(LinkQueue &LQ) {
return LQ.front == LQ.rear; //队头与队为都指向同一个节点即为空
}
入队
/**
* @brief 入队(队尾入队)
*
* @param LQ 链队列
* @param e 入队元素
**/
void enQueue(LinkQueue &LQ, int e) {
LQNode *s = (LQNode *)malloc(sizeof(LQNode));//给入队节点分配空间
s->data = e;//赋值元素
s->next = NULL;//新入队的节点的下一个节点为空
LQ.rear->next = s;//将队尾指针的下一个节点指向新入队的元素
LQ.rear = s;//修改队尾指针,指向新入队的元素
}
出队
/**
* @brief 出队(队头出队)
*
* @param LQ 链队列
* @param e 出队元素
*
* @return 出队是否成功
**/
bool deQueue(LinkQueue &LQ, int &e) {
if (emptyQueue(LQ)) //队列为空,返回false
return false;
LQNode *p = LQ.front->next;//指向队头节点
e = p->data;//队头节点数据
LQ.front->next = p->next;
if (LQ.rear == p) //如果出队的是最后一个节点,就将队列置空
LQ.front = LQ.rear;//若没有这一步,后面释放空间后,队尾指针就丢失了
free(p);
return true;
}
链队列代码汇总
#include <stdio.h>
#include <stdlib.h>
//定义链队列节点
typedef struct LQNode {
int data;//节点数据
struct LQNode *next;//下一个节点指针
} LQNode;
//定义链队列
typedef struct {
LQNode *front, *rear; //队头,队尾指针
} LinkQueue;
//初始化链队列
void initQueue(LinkQueue &LQ) {
LQ.front = LQ.rear = (LQNode *)malloc(sizeof(LQNode));//队头与队尾指针都先指向同一个节点
LQ.front->next = NULL;//队头的下一个节点指向空
}
//判断队空
bool emptyQueue(LinkQueue &LQ) {
return LQ.front == LQ.rear; //队头与队为都指向同一个节点即为空
}
/**
* @brief 入队(队尾入队)
*
* @param LQ 链队列
* @param e 入队元素
**/
void enQueue(LinkQueue &LQ, int e) {
LQNode *s = (LQNode *)malloc(sizeof(LQNode));//给入队节点分配空间
s->data = e;//赋值元素
s->next = NULL;//新入队的节点的下一个节点为空
LQ.rear->next = s;//将队尾指针的下一个节点指向新入队的元素
LQ.rear = s;//修改队尾指针,指向新入队的元素
}
/**
* @brief 出队(队头出队)
*
* @param LQ 链队列
* @param e 出队元素
*
* @return 出队是否成功
**/
bool deQueue(LinkQueue &LQ, int &e) {
if (emptyQueue(LQ)) //队列为空,返回false
return false;
LQNode *p = LQ.front->next;//指向队头节点
e = p->data;//队头节点数据
LQ.front->next = p->next;
if (LQ.rear == p) //如果出队的是最后一个节点,就将队列置空
LQ.front = LQ.rear;//若没有这一步,后面释放空间后,队尾指针就丢失了
free(p);
return true;
}
//显示队列元素
void showQueue(LinkQueue LQ) {
LQNode *p = LQ.front->next;
while (p != NULL) {
if (p->next != NULL)
printf("%d <- ", p->data);
else
printf("%d\n", p->data);
p = p->next;
}
}
int main() {
LinkQueue LQ;
initQueue(LQ);
for (int i = 1; i <= 10; i++) {
enQueue(LQ, i);
}
printf("入队后节点信息为:");
showQueue(LQ);
int e;//记录出队元素
printf("出队元素为:");
for (int i = 1; i <= 5; i++) {
deQueue(LQ, e);
printf("%d ", e);
}
printf("\n");
printf("剩余节点信息为:");
showQueue(LQ);
for (int i = 1; i <= 10; i++) {
enQueue(LQ, i + 10);
}
printf("再入队后,结点信息为:");
showQueue(LQ);
return 0;
}
树
二叉树
定义
//定义二叉树
typedef struct BiNode {
int data;//节点数据
struct BiNode *lChild, *rChild;//左右孩子节点
} BiNode, *BiTree;
先序遍历(递归)
//先序遍历
void preOrder(BiTree T) {
if (T != NULL) {
visit(T);
preOrder(T->lChild);
preOrder(T->rChild);
}
}
中序遍历(递归)
//中序遍历
void inOrder(BiTree T) {
if (T != NULL) {
inOrder(T->lChild);
visit(T);
inOrder(T->rChild);
}
}
后序遍历(递归)
//后序遍历
void postOrder(BiTree T) {
if (T != NULL) {
postOrder(T->lChild);
postOrder(T->rChild);
visit(T);
}
}
层序遍历
//层序遍历
void levelOrder(BiTree &T) {
queue<BiNode *> Q;//初始化队列
BiTree p;
Q.push(T);//根结点入队
while (!Q.empty()) {//队列不空时执行
p = Q.front();//获取队头元素(c++库函数只能先获取到队头元素,然后调用pop出队)
Q.pop();//队头元素出队
visit(p);//访问结点
if (p->lChild != NULL) {//当前结点有左子树时,左子树根结点入队
Q.push(p->lChild);
}
if (p->rChild != NULL) {//当前结点有右子树时,右子树根结点入队
Q.push(p->rChild);
}
}
}
中序遍历(非递归)
//中序遍历(非递归)
void inOrder2(BiTree &T) {
stack<BiNode *> S;//初始化一个栈
BiTree p = T;//p是遍历指针
while (p != NULL || !S.empty()) {//p所指向的结点非空时或者栈不为空时循环
if (p != NULL) {//当前结点非空时,把当前结点入栈,并将遍历指针p指向当前结点的左孩子
S.push(p);
p = p->lChild;//会一直把左还在入栈,直到没有做孩子为止
} else {
p = S.top();//获取栈顶元素(c++库函数只能先获取到栈顶元素,然后调用pop出栈)
S.pop();//出栈
visit(p);//访问当前结点
p = p->rChild;//右孩子入栈
}
}
}
二叉树代码汇总
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
#define Size 10 //节点个数
//定义二叉树
typedef struct BiNode {
int data;//节点数据
struct BiNode *lChild, *rChild;//左右孩子节点
} BiNode, *BiTree;
//初始化一棵二叉树
void initBiTree(BiTree &T) {
T = (BiNode *) malloc(sizeof(BiNode));
T->lChild = T->rChild = NULL; //左右孩子节点置空
}
//为二叉树添加一些测试数据(手动添加)
void addTestData(BiTree &T) {
T->data = 666;
BiNode *b[Size];
for (int i = 0; i < Size; i++) {
b[i] = (BiNode*)malloc(sizeof(BiNode));
b[i]->data = i;
}
T->lChild = b[0];
T->rChild = b[1];
int i = 0, j = 0;
while (i < Size) {
j = 2 * ( i + 1) ;
if (j < Size) {
b[i]->lChild = b[j];
b[i]->rChild = b[j + 1];
} else {
b[i]->lChild = NULL;
b[i]->rChild = NULL;
}
i++;
}
}
//访问节点操作
void visit(BiTree T) {
printf("%d ", T->data);
}
//先序遍历
void preOrder(BiTree T) {
if (T != NULL) {
visit(T);
preOrder(T->lChild);
preOrder(T->rChild);
}
}
//中序遍历
void inOrder(BiTree T) {
if (T != NULL) {
inOrder(T->lChild);
visit(T);
inOrder(T->rChild);
}
}
//后序遍历
void postOrder(BiTree T) {
if (T != NULL) {
postOrder(T->lChild);
postOrder(T->rChild);
visit(T);
}
}
//中序遍历(非递归)
void inOrder2(BiTree &T) {
stack<BiNode *> S;//初始化一个栈
BiTree p = T;//p是遍历指针
while (p != NULL || !S.empty()) {//p所指向的结点非空时或者栈不为空时循环
if (p != NULL) {//当前结点非空时,把当前结点入栈,并将遍历指针p指向当前结点的左孩子
S.push(p);
p = p->lChild;//会一直把左还在入栈,直到没有做孩子为止
} else {
p = S.top();//获取栈顶元素(c++库函数只能先获取到栈顶元素,然后调用pop出栈)
S.pop();//出栈
visit(p);//访问当前结点
p = p->rChild;//右孩子入栈
}
}
}
//层序遍历
void levelOrder(BiTree &T) {
queue<BiNode *> Q;//初始化队列
BiTree p;
Q.push(T);//根结点入队
while (!Q.empty()) {//队列不空时执行
p = Q.front();//获取队头元素(c++库函数只能先获取到队头元素,然后调用pop出队)
Q.pop();//队头元素出队
visit(p);//访问结点
if (p->lChild != NULL) {//当前结点有左子树时,左子树根结点入队
Q.push(p->lChild);
}
if (p->rChild != NULL) {//当前结点有右子树时,右子树根结点入队
Q.push(p->rChild);
}
}
}
int main() {
BiTree T;
initBiTree(T);
addTestData(T);
// preOrder(T);
// inOrder(T);
// inOrder2(T);
// postOrder(T);
levelOrder(T);
return 0;
}
查找
定义顺序表
//多定义一个空间,将0号元素位置置空,作为哨兵使用
#define MaxSize 21
//定义查找表
typedef struct {
int data[MaxSize];//数据
int length;//表长度
} SSTable;
顺序查找
//顺序查找.找到返回元素所在位置,找不到时返回0
int seqSearch(SSTable ST, int key) {
int i;//记录找到元素下标位置
ST.data[0] = key;//哨兵
for (i = ST.length; ST.data[i] != key; --i);//从后往前找。若没有找到,说明此时i已经为0了,返回的是哨兵位置
return i;
}
折半查找(非递归)
//折半查找(非递归)(注意:折半查找需要元素有序)
int binSearch(SSTable ST, int key) {
int low = 0, high = ST.length - 1, mid;
while (low <= high) {
mid = low + (high - low) / 2;//计算中间元素下标
if (key == ST.data[mid])
return mid;//中间位置正好就是待查找元素,直接返回
else if (key < ST.data[mid]) {
high = mid - 1;//从前半部分查找
} else {
low = mid + 1;//从后半部分查找
}
}
return -1;//循环结束都没有返回,说明没有找到,返回-1
}
折半查找(递归)
//折半查找(递归)注意:折半查找需要元素有序)
int binSearchRec(SSTable ST, int key, int low, int high) {
if (low > high) {//递归出口
return -1;
}
int mid = low + (high - low) / 2;//计算中间元素下标
if (key == ST.data[mid]) {
return mid;//中间位置正好就是待查找元素,直接返回
} else if (key < ST.data[mid]) {
binSearchRec(ST, key, low, mid - 1);//从前半部分查找
} else {
binSearchRec(ST, key, mid + 1, high);//从后半部分查找
}
}
查找代码汇总
#include <stdio.h>
#include <stdlib.h>
//多定义一个空间,将0号元素位置置空,作为哨兵使用
#define MaxSize 21
//定义查找表
typedef struct {
int data[MaxSize];//数据
int length;//表长度
} SSTable;
//初始化查找表
void initTable(SSTable &ST) {
ST.length = 0;
}
//添加测试数据(用于顺序查找)
void addTestData1(SSTable &ST) {
for (int i = 1; i <= 10; i++) {
ST.data[i] = i;
ST.length++;
}
}
//添加测试数据(用于折半查找)
void addTestData2(SSTable &ST) {
for (int i = 0; i < 10; i++) {
ST.data[i] = i;
ST.length++;
}
}
//顺序查找.找到返回元素所在位置,找不到时返回0
int seqSearch(SSTable ST, int key) {
int i;//记录找到元素下标位置
ST.data[0] = key;//哨兵
for (i = ST.length; ST.data[i] != key; --i);//从后往前找。若没有找到,说明此时i已经为0了,返回的是哨兵位置
return i;
}
//折半查找(非递归)(注意:折半查找需要元素有序)
int binSearch(SSTable ST, int key) {
int low = 0, high = ST.length - 1, mid;
while (low <= high) {
mid = low + (high - low) / 2;//计算中间元素下标
if (key == ST.data[mid])
return mid;//中间位置正好就是待查找元素,直接返回
else if (key < ST.data[mid]) {
high = mid - 1;//从前半部分查找
} else {
low = mid + 1;//从后半部分查找
}
}
return -1;//循环结束都没有返回,说明没有找到,返回-1
}
//折半查找(递归)注意:折半查找需要元素有序)
int binSearchRec(SSTable ST, int key, int low, int high) {
if (low > high) {//递归出口
return -1;
}
int mid = low + (high - low) / 2;//计算中间元素下标
if (key == ST.data[mid]) {
return mid;//中间位置正好就是待查找元素,直接返回
} else if (key < ST.data[mid]) {
binSearchRec(ST, key, low, mid - 1);//从前半部分查找
} else {
binSearchRec(ST, key, mid + 1, high);//从后半部分查找
}
}
int main() {
SSTable ST;
initTable(ST);
addTestData1(ST);
addTestData2(ST);
for (int i = 1; i <= ST.length; i++) {
printf("%d ", ST.data[i]);
}
printf("\n");
// printf("顺序找到的元素位置为:%d\n", seqSearch(ST, 10));
printf("折半找到的元素位置为:%d\n", binSearch(ST, 10));
printf("折半找到的元素位置为:%d\n", binSearchRec(ST, 10, 0, ST.length - 1));
return 0;
}
排序
插入排序
直接插入排序(不带哨兵)
/**
* @brief 直接插入排序(不带哨兵)
*
* @param arr 待排序数组
* @param arr 数组元素个数
**/
void insertSort(int arr[], int n) {
for (int i = 1; i < n; i++) {//从第二个元素开始
if (arr[i] < arr[i - 1]) {//依次和前一个元素比较,若当前元素比前一个元素小,就说明需要移动元素
int temp = arr[i];//记录下当前元素的数据
int j;//记录元素最后应该插入的位置
for (j = i; temp < arr[j - 1] && j > 0; j--) {//开始找正确的插入位置
arr[j] = arr[j - 1];//比当前元素小的都将往后移
}
arr[j] = temp;//循环结束后,j所指的位置就是当前元素应该插入的位置
}
}
}
直接插入排序(带哨兵,第一个元素不会参与排序)
/**
* @brief 直接插入排序(带哨兵,第一个元素不会参与排序)
*
* @param arr 待排序数组
* @param arr 数组元素个数
**/
void insertSort2(int arr[], int n) {
int i, j;
for (i = 2; i < n; i++) {
if (arr[i] < arr[i - 1]) {
arr[0] = arr[i]; //用第一个元素位置存放比较的元素
for (j = i - 1; arr[0] < arr[j]; j--) {//开始找正确的插入位置
arr[j + 1] = arr[j];//比当前元素小的都将往后移
}
arr[j + 1] = arr[0];//循环结束后,j所指的后一个位置就是当前元素应该插入的位置
}
}
}
折半插入排序
/**
* @brief 折半插入排序(带哨兵,第一个位置元素,不会排序)
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void insertSort3(int arr[], int n) {
int i, j, low, high, mid;
for ( i = 2; i < n; i++) { //从第二个元素开始
if (arr[i] < arr[i - 1]) {
arr[0] = arr[i];//记录下当前元素到哨兵位置
low = 1;
high = i - 1;
while (low <= high) {
mid = low + (high - low) / 2;
if (arr[0] < arr[mid]) { //查左边
high = mid - 1;
} else { //查右边
low = mid + 1;
}
}
//循环退出后,一定是low比high大一,而low所指向的位置恰好就是当前元素应该插入的位置
//开始移动位置
for (j = i - 1; j >= low; j--) {
arr[j + 1] = arr[j];
}
arr[low] = arr[0];//将当前元素插入正确的位置
}
}
}
希尔排序
/**
* @brief 希尔排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void shellSort(int arr[], int n) {
int i, j, dk, temp; //dk为步长,temp用来记录临时值
for (dk = n / 2; dk >= 1; dk /= 2) { //步长变化(当dk == 1的时候,希尔排序就变为了直接插入排序)
for (i = dk; i < n; i++) {
if (arr[i] < arr[i - dk]) {//条件满足时,说明后面的元素比前面的小,需要将当前元素插入到正确的位置
temp = arr[i];//记录当前元素
for (j = i - dk; j >= 0 && temp < arr[j]; j -= dk) {
arr[j + dk] = arr[j];//移动元素
}
arr[j + dk] = temp;//插入到正确位置
}
}
}
}
冒泡排序
/**
* @brief 冒泡排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void bubbleSort(int arr[], int n) {
bool flag;//记录当前是否发生交换
int temp;//辅助交换用的临时变量
for (int i = 0; i < n - 1; i++) {//控制循环次数
flag = false;//本次循环开始时,修改交换标记为false
for (int j = n - 1; j > i; j--) {
if (arr[j] < arr[j - 1]) { //小元素往前冒
temp = arr[j];
arr[j ] = arr[j - 1];
arr[j - 1] = temp;
flag = true;//发生交换后,修改交换标记为true
}
}
if (!flag) //本次循环没有发生交换,说明已排好序,退出循环
break;
}
}
快速排序
/**
* @brief 快排的划分操作
*
* @param arr 待排序数组
* @param low 待排序区域第一个元素下标
* @param high 待排序区域最后一个元素下标
*
* @return 放枢轴元素的位置
**/
int partition(int arr[], int low, int high) {
int pivot = arr[low];//将第一个元素作为枢轴值
while (low < high) { //跳出循环条件
while (low < high && arr[high] >= pivot) {//从右往左开始,找到第一个比枢轴值小的元素
high--;//循环满足,说明当前元素比枢轴值大,此时需要继续往左找
}
arr[low] = arr[high];//将比枢轴值小的元素移动到左端
while (low < high && arr[low] <= pivot) {//从左往右开始,找到第一个比枢轴值大的元素
low++;//循环满足,说明当前元素比枢轴值小,此时需要继续往右找
}
arr[high] = arr[low];//将比枢轴值大的元素移动到右端
}
arr[low] = pivot;//枢轴元素存放到最终位置
return low;//返回存放枢轴元素的位置
}
/**
* @brief 快速排序
*
* @param arr 待排序数组
* @param low 待排序区域第一个元素下标
* @param high 待排序区域最后一个元素下标
**/
void quickSort(int arr[], int low, int high) {
if (low < high) { //递归出口(low >= high时,划分结束,排序完成)
int pivot = partition(arr, low, high); //划分
quickSort(arr, low, pivot - 1); //前部分继续排序
quickSort(arr, pivot + 1, high); //前部分继续排序
}
}
简单选择排序
/**
* @brief 选择排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void selectSort(int arr[], int n) {
int min, temp;//min记录最小元素的下标,temp交换的临时变量
for (int i = 0; i < n; i++) {
min = i;//记录最小元素下标
for (int j = i + 1; j < n; j++) {//往后找,比当前元素小的元素下标
if (arr[min] > arr[j]) {
min = j;//更新最小元素的下标
}
}
if (min != i) {//后面有比当前元素小的元素才交换
//将找到的最小元素交换到前面
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
}
堆排序
/**
* @brief 将以k为根的子树调整为大根堆
*
* @param arr 待排序数组
* @param k 待调整元素下标
* @param n 数组元素个数
**/
void adjustDown(int arr[], int k, int n) {
arr[0] = arr[k];//数组第一个位置用来暂存当前待调整元素
for (int i = 2 * k; i <= n; i *= 2) {// 2 * k表示k的左孩子
if (i < n && arr[i] < arr[i + 1])//i < n说明存在右孩子,若左孩子小于右孩子,i记录的最大值更新为右孩子
i++;
if (arr[0] >= arr[i])//如果当前元素比孩子节点最大值大,就不用调整,直接break
break;
else {//需要调整
arr[k] = arr[i];//k所指节点的数据更新为孩子中较大的一个值,更新后,可能造成原本是大根堆的树,不满足大根堆条件,需要再次判断
k = i;//将原来待调整的节点k,更新为判断i这个节点是否符合大根堆条件。该过程可以看作小元素下坠。
}
}
arr[k] = arr[0];//最后,将原本k所指的数据(在0号位置备份的数据),放到新的k所指位置。
}
/**
* @brief 创建大根堆
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void buildMaxHeap(int arr[], int n) {
for (int i = n / 2; i > 0; i--) {//从最后一个非叶子结点往前检查,依次调整为大根堆
adjustDown(arr, i, n);//检查当前节点,并将该节点调整为大根堆
}
}
/**
* @brief 堆排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void heapSort(int arr[], int n) {
buildMaxHeap(arr, n);//构建大根堆
for (int i = n; i > 1; i--) {//从最后一个位置开始,依次将每一个堆顶元素交换到堆底,交换后的元素再次调整为大根堆
swap(arr[i], arr[1]);
adjustDown(arr, 1, i - 1);
}
}
归并排序
/**
* @brief 归并过程
*
* @param arr 待排序数组
* @param low 待排序序列的第一个元素下标
* @param mid 排序序列的中间元素下标
* @param high 排序序列的最后一个元素下标
**/
void merge(int arr[], int low, int mid, int high) {
int res[high - low + 1];//辅助数组(辅助数组大小通过计算获得)
int k = 0;//记录辅助数组起始下标
int i = low;//记录左边部分起始下标
int j = mid + 1;//记录右边部分起始下标
while (i <= mid && j <= high) {//左右部分均还有元素时,比较两个部分的大小
if (arr[i] <= arr[j]) {//如果左边的小或者两者相等,就将左边的数据放到辅助数组中
res[k++] = arr[i++];//赋值,并修改辅助数组以及左边部分的下标
} else {//如果右边的小,就将右边的数据放到辅助数组中
res[k++] = arr[j++];//赋值,并修改辅助数组以及右边部分的下标
}
}
//上面while循环结束后,i,j中必有一个走到了末尾,则下面的两个while循环,仅会执行一个
while (i <= mid)//左边部分还有剩余,将左边剩余的全部复制到辅助数组中
res[k++] = arr[i++];
while (j <= high)//右边部分还有剩余,将右边剩余的全部复制到辅助数组中
res[k++] = arr[j++];
for (i = low, j = 0 ; j < k; i++, j++)//将辅助数组中的元素复制到原来数组中
arr[i] = res[j];
}
/**
* @brief 归并排序
*
* @param arr 待排序数组
* @param low 待排序序列的第一个元素下标
* @param high 排序序列的最后一个元素下标
**/
void mergeSort(int arr[], int low, int high) {
if (low < high) {
int mid = low + (high - low) / 2;
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
merge(arr, low, mid, high);
}
}
排序代码汇总
#include <stdio.h>
#include <stdlib.h>
//交换两个元素
void swap(int &x, int &y) {
int temp = x;
x = y;
y = temp;
}
/**
* @brief 直接插入排序(不带哨兵)
*
* @param arr 待排序数组
* @param arr 数组元素个数
**/
void insertSort(int arr[], int n) {
for (int i = 1; i < n; i++) {//从第二个元素开始
if (arr[i] < arr[i - 1]) {//依次和前一个元素比较,若当前元素比前一个元素小,就说明需要移动元素
int temp = arr[i];//记录下当前元素的数据
int j;//记录元素最后应该插入的位置
for (j = i; temp < arr[j - 1] && j > 0; j--) {//开始找正确的插入位置
arr[j] = arr[j - 1];//比当前元素小的都将往后移
}
arr[j] = temp;//循环结束后,j所指的位置就是当前元素应该插入的位置
}
}
}
/**
* @brief 直接插入排序(带哨兵,第一个位置元素不会参与排序)
*
* @param arr 待排序数组
* @param arr 数组元素个数
**/
void insertSort2(int arr[], int n) {
int i, j;
for (i = 2; i < n; i++) {//从第二个元素开始
if (arr[i] < arr[i - 1]) {
arr[0] = arr[i]; //用第一个元素位置存放比较的元素
for (j = i - 1; arr[0] < arr[j]; j--) {//开始找正确的插入位置
arr[j + 1] = arr[j];//比当前元素小的都将往后移
}
arr[j + 1] = arr[0];//循环结束后,j所指的后一个位置就是当前元素应该插入的位置
}
}
}
/**
* @brief 折半插入排序(带哨兵,第一个位置元素,不会排序)
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void insertSort3(int arr[], int n) {
int i, j, low, high, mid;
for ( i = 2; i < n; i++) { //从第二个元素开始
if (arr[i] < arr[i - 1]) {
arr[0] = arr[i];//记录下当前元素到哨兵位置
low = 1;
high = i - 1;
while (low <= high) {
mid = low + (high - low) / 2;
if (arr[0] < arr[mid]) { //查左边
high = mid - 1;
} else { //查右边
low = mid + 1;
}
}
//循环退出后,一定是low比high大一,而low所指向的位置恰好就是当前元素应该插入的位置
//开始移动位置
for (j = i - 1; j >= low; j--) {
arr[j + 1] = arr[j];
}
arr[low] = arr[0];//将当前元素插入正确的位置
}
}
}
/**
* @brief 希尔排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void shellSort(int arr[], int n) {
int i, j, dk, temp; //dk为步长,temp用来记录临时值
for (dk = n / 2; dk >= 1; dk /= 2) { //步长变化(当dk == 1的时候,希尔排序就变为了直接插入排序)
for (i = dk; i < n; i++) {
if (arr[i] < arr[i - dk]) {//条件满足时,说明后面的元素比前面的小,需要将当前元素插入到正确的位置
temp = arr[i];//记录当前元素
for (j = i - dk; j >= 0 && temp < arr[j]; j -= dk) {
arr[j + dk] = arr[j];//移动元素
}
arr[j + dk] = temp;//插入到正确位置
}
}
}
}
/**
* @brief 希尔排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void shellSort2(int arr[], int n) {
int i, j, dk; //dk为步长
for (dk = n / 2; dk >= 1; dk /= 2) { //步长变化
for (i = dk + 1; i < n; i++) {
if (arr[i] < arr[i - dk]) {
arr[0] = arr[i];//暂存在arr[0]
for (j = i - dk; j > 0 && arr[0] < arr[j]; j -= dk) {
arr[j + dk] = arr[j];
}
arr[j + dk] = arr[0];
}
}
}
}
/**
* @brief 冒泡排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void bubbleSort(int arr[], int n) {
bool flag;//记录当前是否发生交换
for (int i = 0; i < n - 1; i++) {//控制循环次数
flag = false;//本次循环开始时,修改交换标记为false
for (int j = n - 1; j > i; j--) {
if (arr[j] < arr[j - 1]) { //小元素往前冒
swap(arr[j], arr[j - 1]);
flag = true;//发生交换后,修改交换标记为true
}
}
if (!flag) //本次循环没有发生交换,说明已排好序,退出循环
break;
}
}
/**
* @brief 快排的划分操作
*
* @param arr 待排序数组
* @param low 待排序区域第一个元素下标
* @param high 待排序区域最后一个元素下标
*
* @return 返回枢轴元素的位置
**/
int partition(int arr[], int low, int high) {
int pivot = arr[low];//将第一个元素作为枢轴值
while (low < high) { //跳出循环条件
while (low < high && arr[high] >= pivot) {//从右往左开始,找到第一个比枢轴值小的元素
high--;//循环满足,说明当前元素比枢轴值大,此时需要继续往左找
}
arr[low] = arr[high];//将比枢轴值小的元素移动到左端
while (low < high && arr[low] <= pivot) {//从左往右开始,找到第一个比枢轴值大的元素
low++;//循环满足,说明当前元素比枢轴值小,此时需要继续往右找
}
arr[high] = arr[low];//将比枢轴值大的元素移动到右端
}
arr[low] = pivot;//枢轴元素存放到最终位置
return low;//返回存放枢轴元素的位置
}
/**
* @brief 快速排序
*
* @param arr 待排序数组
* @param low 待排序区域第一个元素下标
* @param high 待排序区域最后一个元素下标
**/
void quickSort(int arr[], int low, int high) {
if (low < high) { //递归出口(low >= high时,划分结束,排序完成)
int pivot = partition(arr, low, high); //划分
quickSort(arr, low, pivot - 1); //前部分继续排序
quickSort(arr, pivot + 1, high); //前部分继续排序
}
}
/**
* @brief 选择排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void selectSort(int arr[], int n) {
int min;//min记录最小元素的下标
for (int i = 0; i < n; i++) {
min = i;//记录最小元素下标
for (int j = i + 1; j < n; j++) {//往后找,比当前元素小的元素下标
if (arr[min] > arr[j]) {
min = j;//更新最小元素的下标
}
}
if (min != i) {//后面有比当前元素小的元素才交换
//将找到的最小元素交换到前面
swap(arr[i], arr[min]);
}
}
}
/**
* @brief 将待调整元素k向上调整(主要用于删除堆元素后)
*
* @param arr 待排序数组
* @param k 待调整元素下标
**/
void adjustUp(int arr[], int k) {
arr[0] = arr[k];//数组第一个位置用来暂存当前待调整元素
int i = k / 2;
while (i > 0 && arr[i] < arr[0]) {
arr[k] = arr[i];
k = i;
i = k / 2;
}
arr[k] = arr[0];
}
/**
* @brief 将以k为根的子树调整为大根堆
*
* @param arr 待排序数组
* @param k 待调整元素下标
* @param n 数组元素个数
**/
void adjustDown(int arr[], int k, int n) {
arr[0] = arr[k];//数组第一个位置用来暂存当前待调整元素
for (int i = 2 * k; i <= n; i *= 2) {// 2 * k表示k的左孩子
if (i < n && arr[i] < arr[i + 1])//i < n说明存在右孩子,若左孩子小于右孩子,i记录的最大值更新为右孩子
i++;
if (arr[0] >= arr[i])//如果当前元素比孩子节点最大值大,就不用调整,直接break
break;
else {//需要调整
arr[k] = arr[i];//k所指节点的数据更新为孩子中较大的一个值,更新后,可能造成原本是大根堆的树,不满足大根堆条件,需要再次判断
k = i;//将原来待调整的节点k,更新为判断i这个节点是否符合大根堆条件。该过程可以看作小元素下坠。
}
}
arr[k] = arr[0];//最后,将原本k所指的数据(在0号位置备份的数据),放到新的k所指位置。
}
/**
* @brief 创建大根堆
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void buildMaxHeap(int arr[], int n) {
for (int i = n / 2; i > 0; i--) {//从最后一个非叶子结点往前检查,依次调整为大根堆
adjustDown(arr, i, n);//检查当前节点,并将该节点调整为大根堆
}
}
/**
* @brief 堆排序
*
* @param arr 待排序数组
* @param n 数组元素个数
**/
void heapSort(int arr[], int n) {
buildMaxHeap(arr, n);//构建大根堆
for (int i = n; i > 1; i--) {//从最后一个位置开始,依次将每一个堆顶元素交换到堆底,交换后的元素再次调整为大根堆
swap(arr[i], arr[1]);
adjustDown(arr, 1, i - 1);
}
}
//
///**
// * @brief 归并过程
// *
// * @param arr 待排序数组
// * @param low 待排序序列的第一个元素下标
// * @param mid 排序序列的中间元素下标
// * @param high 排序序列的最后一个元素下标
// **/
//void merge(int arr[], int low, int mid, int high) {
// int i, j, k;//记录下标变量
// int temp[high - low + 1];//辅助数组
// for (k = low; k <= high; k++)//将待排序数组,复制一份到辅助数组
// temp[k] = arr[k];
// for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
// if (temp[i] <= temp [j]) //比较辅助数组左右两段中的元素
// arr[k] = temp[i++];
// else
// arr[k] = temp[j++];
// }
// while (i <= mid)
// arr[k++] = temp[i++];
// while (j <= high)
// arr[k++] = temp[j++];
//}
//
///**
// * @brief 归并排序
// *
// * @param arr 待排序数组
// * @param low 待排序序列的第一个元素下标
// * @param high 排序序列的最后一个元素下标
// **/
//void mergeSort(int arr[], int low, int high) {
// if (low < high) {
// int mid = low + (high - low) / 2;//从中间划分两个子序列
// mergeSort(arr, low, mid); //对左边部分进行归并排序
// mergeSort(arr, mid + 1, high); //对右边部分进行归并排序
// merge(arr, low, mid, high); //归并操作
// }
//}
/**
* @brief 归并过程
*
* @param arr 待排序数组
* @param low 待排序序列的第一个元素下标
* @param mid 排序序列的中间元素下标
* @param high 排序序列的最后一个元素下标
**/
void merge(int arr[], int low, int mid, int high) {
int res[high - low + 1];//辅助数组(辅助数组大小通过计算获得)
int k = 0;//记录辅助数组起始下标
int i = low;//记录左边部分起始下标
int j = mid + 1;//记录右边部分起始下标
while (i <= mid && j <= high) {//左右部分均还有元素时,比较两个部分的大小
if (arr[i] <= arr[j]) {//如果左边的小或者两者相等,就将左边的数据放到辅助数组中
res[k++] = arr[i++];//赋值,并修改辅助数组以及左边部分的下标
} else {//如果右边的小,就将右边的数据放到辅助数组中
res[k++] = arr[j++];//赋值,并修改辅助数组以及右边部分的下标
}
}
//上面while循环结束后,i,j中必有一个走到了末尾,则下面的两个while循环,仅会执行一个
while (i <= mid)//左边部分还有剩余,将左边剩余的全部复制到辅助数组中
res[k++] = arr[i++];
while (j <= high)//右边部分还有剩余,将右边剩余的全部复制到辅助数组中
res[k++] = arr[j++];
for (i = low, j = 0 ; j < k; i++, j++)//将辅助数组中的元素复制到原来数组中
arr[i] = res[j];
}
/**
* @brief 归并排序
*
* @param arr 待排序数组
* @param low 待排序序列的第一个元素下标
* @param high 排序序列的最后一个元素下标
**/
void mergeSort(int arr[], int low, int high) {
if (low < high) {
int mid = low + (high - low) / 2;
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
merge(arr, low, mid, high);
}
}
//显示排序后的数据
void show(int arr[], int n, bool flag = false) {
//flag为true时,说明第一个元素是哨兵,遍历时,从下标为1开始。
for (int i = flag ? 1 : 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[] = { 5, 4, 2, 3, 8, 1, 6, 7, 9, 10, 15, 14, 12, 11, 13};
int n = sizeof(arr) / sizeof(int);//计算数组元素个数
//插入排序
// insertSort(arr, n);
// printf("不带哨兵插入排序后\n");
// show(arr, n);
// insertSort2(arr, n);
// printf("带哨兵插入排序后\n");
// show(arr, n, true);
// insertSort3(arr, n);
// printf("带哨兵折半插入排序后\n");
// show(arr, n, true);
// shellSort(arr, n);
// printf("希尔排序后\n");
// show(arr, n);
// bubbleSort(arr, n);
// printf("冒泡排序后\n");
// show(arr, n);
// quickSort(arr, 0, n - 1);
// printf("快速排序后\n");
// show(arr, n);
// selectSort(arr, n);
// printf("简单选择排序后\n");
// show(arr, n);
// heapSort(arr, n - 1);
// printf("堆排序后\n");
// show(arr, n, true);
mergeSort(arr, 0, n - 1);
printf("归并排序后\n");
show(arr, n);
return 0;
}