第一章.线性表
1.1 顺序表的基本操作
1.结点类型描述
#define MaxSize 100 //定义线性表的最大长度
typedef struct{
ElemType *data; //顺序表的元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义
2.插入操作
对于插入操作,若表长为n,则在第i个位置(即下标为i-1)插入元素e,则从an-1到ai-1都要向后移动一个位置,共需移动n-i+1个元素,平均时间复杂度为O(n)。
int ListInsert(SqList *L,int i,ElemType e){
if(i<1 || i>L->length+1) return -1; //判断i的范围是否合法
if(L->length=MaxSize) return -1; //判断当前存储空间是否已满
for(int j=L->length;j>=i;j--){
L->data[j]=L->data[j-1]; //将第i个位置及之后的元素后移
}
L->data[i-1]=e; //在第i个位置放入e,数组从0开始储存
L->length++; //线性表长度加1
retrun 0;
}
3.删除操作
对于删除算法,若表长为n,当删除第i个元素时,从ai到an-1都要向前移动一个位置,则共需移动n-i个元素,平均时间复杂度为O(n)。
int ListDelete(SqList *L,int i){
if((i<1)||(i>L->ltngth) retrun -1; //判断i的范围是否有效
for(int j=i;j<L->length;j++){
L->data[j-1]=L->data[j] //将第i个位置之后的元素前移
}
L->length--; //线性表长度减1
return 0;
}
4.查找操作
按序号查找。顺序表具有随机存取(根据首地址和序号)的特点,时间复杂度为O(1). 按值查找。主要运算是比较操作,比较的次数与值在表中的位置有关,也与表长n有关,平均比较次数为(n+1)/2,时间复杂度为O(n)。
//按序号查找
int GetElem(SqList *L,int i,ElemType *e){
if(i<1 || i>L->length) return -1;
*e=L->data[i-1];
retrun 0;
}
//按值查找
int LocateElem(SqList *L,ElemType e){
for(int i=0;i<L->length;i++){
if(L->data[i]==e) retrun i++;
}
return 0;
}
5.其他操作
//线性表的初始化
int InitList(SqList *L){
L->data=(int *)malloc(MaxSize*sizeof(int));
if(!L->data) return -1;
L->length=0;
return 0;
}
//销毁线性表
void DestoryList(SqList *L){
free(L->data);
L->length=0;
L->data=NULL;
}
//清空线性表
void CleanList(SqList *L){
L->length=0;
}
//求线性表长度
int GetLength(SqList *L){
return L->length;
}
//判断线性表是否为空
int IsEmpty(SqList *L){
if(L->length==0) return 0;
else return 1;
}
1.2链表的基本操作
1.结点类型描述
typedef struct Lnode{
int data;
struct Lnode* next;
}LNode,*LinkList;
2.头插法创建单链表
从一个空表开始,将新结点插入当前链表的表头,即头结点之后。采用头插法建立单链表的算法虽然简单,但读入数据的顺序与生成的链表中元素的顺序是相反的。每个结点插入的时间复杂度为O(1),设单链表表的表长为n,总时间复杂度为O(n)。
注意:1.2的顺序不能换,否则会造成断链。
void CreateList_H(LinkList L){
int n;
LinkList p;
while(scanf("%d",&n)){
p=(LinkList)malloc(sizeof(LNode));
p->data=n;
p->next=L->next; //1.新结点的指针指向原链表的第一个结点
L->next=p; //2.头结点的指针指向新节点,L为头指针
}
}
3.尾插法创建单链表
若希望读入数据的顺序与生成的链表中元素的顺序一致,可以采用尾插法,即将新结点插入当前链表的表尾,为此必须增加一个尾指针r,使其始终指向当前链表的尾节点。尾插法附设了一个指向表尾结点的指针,其时间复杂度和头插法相同,也为O(n)。
void CreateList_R(LinkList L){
int n;
LinkList p,r=L;
while(scanf("%d",&n)){
p=(LinkList)malloc(sizeof(LNode));
p->data=n;
p->next=NULL;
r->next=p; //原链表中的尾节点(r所指)的指针指向新结点
r=p; //r指向新的尾节点
}
}
4.查找操作
按序号查找:在单链表中,从第一个结点出发,顺着指针next域逐个向下搜索,直到找到第i个结点为止,并返回该结点的指针,否则返回NULL。 按值查找:从单链表第一个结点开始,由前往后依次比较表中各节点的数据域,若某结点数据域的值等于给定值e,则返回该节点的指针。若找不到这样的系欸但,则返回NULL。
//按序号查找
int GetElem(LinkList L,int i){
LinkList p=L;
for(int j=0;p&&j<i;j++){
p=p->next;
}
if(p==NULL||i==0) retrun -1;
else return p->data;
}
//按值查找
int LocateElem(LinkList L,int i){
int j=1;
LinkList p=L->next;
for(int j=1;p&&p->data!=i;j++){
p=p->next;
}
if(p) return j;
else return -1;
}
5.插入操作
插入操作是将值为x的新结点插入单链表的第i个位置。先检查插入位置的合法性,然后找到带插入位置的前驱结点,即第i-1个结点,再在其后插入新的结点。插入操作的算法时间开销在于查找第i-1个元素,时间复杂度为O(n);若是在给定的结点后插入新结点,则时间复杂度为O(1)。
int InsertList(LinkList L,int i,int ElemType e){
LiskList p=L;
for(int j=0;p&&j<i-1;j++){//查找插入位置的前驱结点
p=p->next;
}
s=new LNode; //待插入结点
s->data=e;
s->next=p->next;
p->next=s;
return 0;
}
6.删除操作
删除操作是将单链表的第i个结点删除。先检查删除位置的合法性,然后查找表中第i-1个结点,即被删结点的前驱结点,再将其删除。
int DeleteList(LinkList *L,int i){
LinkList p=*L,q;
for(int j=0;p&&j<i-1;j++){ //查找删除位置的前驱结点
p=p->next;
}
if(!(p->next)||j>i-1) return -1;
q=p->next; //令q指向被删结点
p->next=q->next; //将q结点从链中断开
free(q); //释放被删结点的存储空间
return 0;
}
7.求表长操作
计算单链表中数据结点(含头结点)的个数,从第一个结点开始依次顺序访问表中每个结点,为次需要设置一个计数器变量,每访问一个结点计数器加1,直到访问到NULL为止,时间复杂度为O(n)。
int LengthList(LinkList L){
LinkList p=L->next;
for(int len=0;p;len++){
p=p->next;
}
return len;
}
8.其他操作
//单链表的初始化
int InitList(LinkList *L){
*L=(LinkList)malloc(sizeof(LNode));
(*L)->next=NULL;
return 0;
}
//单链表的销毁
int DestoryList(LinkList L){
LinkList p;
while(L){
p=L;
L=L->next;
free(p)
}
return 0;
}
//单链表的清空
int CleanList(LinkList L){
LinkList p,q;
p=L->next;
while(p){
q=p->next;
free(p);
p=q;
}
L->next=NULL;
return 0;
}
//判断单链表是否为空
int IsEmpty(LiskList L){
if(L-next) retrun 0;
return 1;
}
1.3 双链表的基本操作
1.结点类型描述
typedef struct DNode{
ElemType data;
struct DNode *prior ,*next;
}DNode,*DLinkList;
2.插入操作
int InsertList(DLinkList DL,int i,int ElemType e){
DLiskList p=DL;
for(int j=0;p&&j<i=-1;j++){
p=p->next;
}
s=new DNode;
s->data=e;
s->next=p->next;
p->next->prior=s;
s->prior=p;
p->next=s;
return 0;
}
3.删除操作
int DeleteList(DLinkList DL,int i){
DLinkList p=DL,q;
for(int j=0;p&&j<i-1;j++){
p=p->next;
}
if(!(p->next)||j>i-1) return -1;
q=p->next;
p->next=q->next;
q->next->prior=p;
free(q);
return 0;
}
第二章.栈和队列
2.1 顺序栈的基本操作
1.顺序栈的存储类型描述
#define MaxSize 50 //定义栈中元素的最大个数
typedef struct{
ElemType *data; //存放栈中元素
int top; //栈顶指针
}SqStack;
栈顶指针为top, 初始时设置top=-1,栈顶元素data[top]。
入栈操作:暂未满时,先将栈顶指针加1,再送值到栈顶存储单元。
出栈操作:栈非空时,先取栈顶元素值,再将栈顶指针减1。
栈空条件:top==-1。栈满条件:top=MaxSize-1。栈长:top+1
2.入栈操作
int Push(SqStack *s,Elemtype e){
if(s->top==MaxSize-1) return -1; //栈满报错
s->data[++(s->top)]=e; //指针先加一,在入栈
}
3.出栈操作
int Push(SqStack *s){
if(s->top==-1) return -1; //栈空报错
return s->data[(s->top)--]; //先出栈,指针再减1
}
4.其他操作
//顺序栈的初始化
void InistStack(SqStack *s){
s->data=(int *)malloc(MaxSize*sizeof(int));
s->top=-1;
return 0;
}
//求栈的长度
int StackLength(SqStack *s){
return s->top+1;
}
//判断栈是否为空
int StackEmpty(SqStaack *s){
if(s->top==-1) return 0;
return -1;
}
//清空栈
int CleanStack(SqStack *s){
s->top=-1;
return 0;
}
//销毁栈
int DestoryStack(SqStack *s){
s->top=-1;
free(s->data);
return 0;
}
2.2 链栈的基本操作
1.链栈的存储类型描述
typedef struct StackNode{
Elemtype data; //数据域
struct StackNode *next; //指针域
}StackNode,*linkStack;
2.入栈操作
void Push(LinkStack *S, Elemtype e) { //类似于头插法创建单链表
LinkStack p;
p = (LinkStack)malloc(sizeof(StackNode));
p->data = e;
p->next = *S;
(*S) = p;
}
3.出栈操作
int Pop(LinkStack *S) {
LinkStack p;
if (*S == NULL) return INT_MIN;
p = *S;
*S = (*S)->next;
int pop = p->data;
free(p);
return pop;
}
4.其他操作
//链栈的初始化
void InitStack(LinkStack* S) {
*S = NULL;
}
//链栈判空
int StackEmpty(LinkStack S) {
if (S == NULL) return 0;
else return 1;
}
//取栈顶元素
int GetTop(LinkStack S) {
return S->data;
}
//获取链栈的长度
int GetLen(LinkStack S) {
int i = 0;
while (S) {
i++;
S = S->next;
}
return i;
}
//销毁栈
int DestoryStack(LinkStack* S) {
LinkStack p;
while (*S) {
p = *S;
*S = (*S)->next;
free(p);
}
*S = NULL;
return 0;
}
2.3 栈的应用
1.数制转换
将十进制转换成其他进制(辗转相除法)。将所得余数倒过来就是所求进制的值。
#include <stdio.h>
#include <stdlib.h>
//顺序栈的基本内容省略(采用了全局栈)
static void conversion(int i,int j) { //将任意十进制数转成其他任意进制
while (i>0) {
push(i % j);
i = i / j;
}
while(s.top!=-1)
printf("%d", pop());
}
int main(int argc, char* argv[]){
initStack();
int i = 159, j = 8;
conversion(i,j);
return 0;
}
2.括号匹配
#include <stdio.h>
#include <stdlib.h>
//链栈的基本操作省略
int matching(LinkStack* S, char* ch, int* j) {
while (*ch != '\0') {
if ((*ch == '(') || (*ch == '[') || (*ch == '{')) Push(S, *ch); //遇见左括号就入栈
else if (*ch == ')') {
if (IsEmpty(S) == 0) return 0; //没有与之匹配的左括号
else if (GetTop(S) == '(') Pop(S); //成功匹配
else return 0; //匹配到不同类型的左括号
}
else if (*ch == ']') {
if (IsEmpty(S) == 0) return 0;
else if (GetTop(S) == '[') Pop(S);
else return 0;
}
else if (*ch == '}') {
if (IsEmpty(S) == 0) return 0;
else if (GetTop(S) == '{') Pop(S);
else return 0;
}
ch++;
}
if (IsEmpty(S) == 0) return 1; //所有括号都能配对,没有多余的括号
else return 0;
}
int main(int argc, char* argv[])
{
LinkStack S;
int j = 1;
char ch[] = "[]({}())"; //待匹配字符串
InitStack(&S);
if (matching(&S, ch, &j)) printf("匹配成功!!!\n");
else printf("匹配失败!!!\n");
return 0;
}
3.中缀表达式转后缀表达式(逆波兰式)
算法流程:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 20
//链栈的基本操作省略
void conversion(SqStack* S1, SqStack* S2, char* lum) {
while ((*lum) != '\0') {
if ((*lum) == '+' || (*lum) == '-') {
if (GetHead(S1) == '*' || GetHead(S1) == '%') {
while (GetHead(S1) == '*' || GetHead(S1) == '%' || GetHead(S1) == '+' || GetHead(S1) == '-') {
Push(S2, Pop(S1));
}
Push(S1, *lum);
}
else Push(S1, *lum);
}
else if ((*lum) == '*' || (*lum) == '%') Push(S1, *lum);
else if ((*lum) == '(') Push(S1, *lum);
else if ((*lum) == ')') { //遇到右括号
while (GetHead(S1) != '(') {
Push(S2, Pop(S1));
}
Pop(S1); //弹出左括号
}
else{ //遇到操作数
Push(S2, *lum);
}
lum++;
}
while (GetHead(S1) != '\0') { //将S1中最后剩下的几个运算符压入S2
Push(S2, Pop(S1));
}
}
int main(int argc, char* argv[])
{
SqStack S1,S2;
char lum[] = "a+b*c+(d*e+f)*g"; //后缀表达式:abc*+de*f+g*+
InitStack(&S1);
InitStack(&S2);
conversion(&S1, &S2, lum);
while (S2.top != S2.base) { //S2装的是后缀表达式的倒序
Push(&S1, Pop(&S2));
}
while (S1.top != S1.base) {
printf("%c",Pop(&S1));
}
DestoruyStack(&S1);
DestoruyStack(&S2);
return 0;
}
4.后缀表达式的计算
当遇到数值的时候入栈,当遇到运算符的时候,连续两次出栈,将两结果当成新遇到的数值入栈。如此往复,直到扫描到终止符此时栈底元素值即为表达式的值。
2.4 循环队列的基本操作
1.队列的顺序存储类型描述
#define MaxSize 50
typedef struct{
Elemtype *data;
int front,rear;
}SqQueue;
2.入队操作
int EnQueue(SqQueue *Q,Elemtype e){
if((Q->rear+1)%MaxSize==Q->front) return -1; //队满
Q->data[Q->rear]=e;
Q->rear=(Q->rear+1)%MaxSize; //队尾指针加1取模
return 0;
}
3.出队操作
int DeQueue(SqQueue *Q){
if(Q->front==Q->rear) return -1; //队空
Elemtype e=Q->data[Q->front];
Q->front=(Q->front+1)%MaxSize; //对头指针加1取模
return 0;
}
4.其他操作
//顺序队列的初始化
void InitQueue(SqQueue *Q){
Q->data=(SqQueue*)malloc(MaxSize*sizeof(SqQUeue));
Q->front=Q->rear=0;
}
//求队列的长度
int QueueLength(SqQueue *Q){
return ((Q->rear-Q->front+MaxSize)%MaxSize);
}
//取队头元素
Elemtype GetHead(SqQueue *Q){
if(Q->front!=Q->rear) return Q->data[Q->front];
2.5 链队列的基本操作
1.队列的链式存储类型描述(带头结点)
#define MaxSize 50
typedef struct Qnode{ //链队列结点
Elemtype data;
struct Qnode *next;
}QNode;
typedef struct{ //链式队列
QNode *front,*rear;
}LinkQueue;
2.入队操作
int EnQueue(LinkQueue *Q,Elemtype e){
QNode* p=(QNode*)malloc(sizeof(QNode));
p->data=e;
p->next=NULL;
Q->rear->next=p;
Q->rear=p;
return 0;
}
3.出队操作
Elemtype DeQueue(LinkQueue *Q){
if(Q.front==Q.rear) return -1;
QNode* p=Q-.front->next;
Q.front->next=p->next
if(Q->rear==p) Q->rear==q->front;
free(p);
return 0;
}
4.其他操作
//链队列的初始化
void InitQueue(LinkQueue *Q){
Q->front=Q->rear=(QNode*)malloc(sizeof(QNode));
Q->front->next=NULL;
return 0;
}
//求队头元素
Elemtype GetHead(LinkQueue *Q){
if(Q->front==Q->rear) return -1;
return Q->front->next->data;
}
//销毁链队列
int DestoryQueue(LinkQueue *Q){
while(Q->front){
QNode* p=Q->front;
Q->front=Q->front->next;
free(p);
}
return 0;
}
第三章.串
3.1 串的顺序存储结构
#define MaxSzie 50
typedef struct{
char *data;
int length; //串的实际长度
}SString;
3.2 串的链式存储结构
typedef struct StringNode{
char ch;
struct StringNode *next;
}StringNode,*String;
3.3 串的匹配算法
1. BF算法(朴素匹配算法或暴力匹配算法)
时间复杂度:O(nm)(n为主串的长度,m为模式串的长度)
int Index_BF(SString S,SString T){
int i=1,j=1;
while(i<=S.length&&j<T.length){
if(S.ch[i]==T.ch[j]){
i++; //主串和字串依次匹配下一个字符
j++; //主串字串回溯重新开始下一次匹配
}
else{
i=i-j+2;
j=1;
}
}
if(j==T.length) return i-T.length; //返回匹配的第一个字符的下标
else return 0; //模式匹配不成功
}
2. KMP算法
时间复杂度为O(n+m)(求next数组的时间复杂度为O(m),模式匹配过程的时间复杂度为O(n))
int Index_KMP(SString S,SString T,int next[]){//模式匹配
int i=1,j=1;
while(i<S.length&&j<T.length){
if(j==0||S.ch[i]==T.ch[j]){
i++;
j++;
}
else j=next[j];
}
if(j==T.length) return i-T.length;
else return 0;
}
int* GetNext(SString T,int next[]){
int i=1,j=0;
next[1]=0;
while(i<=T.length){
if(j==0||T.ch[i]==T.ch[j]) next[++i]=++j;
else j=next[i];
}
return next;
}
int* GetNextVel(SString T,int nextvel[]){
int i=1,j=0;
nextval[1]0;
while(i<=T.length){
if(j==0||T.ch[i]==T.ch[j]){
if(T.ch[i]!=T.ch[j]) nextval[++i]=++j;
else nextval[i]=nextval[j]
}
else j=next[i];
}
return nextval;
}
第四章.树与二叉树
4.1 二叉树
4.1.1 二叉树的存储结构
1.二叉树的顺序存储结构
注意:顺序存储结构只适合存储完全二叉树。
#define MaxSize 100
struct TreeNode{
Elemtype data;
bool isEmpty;
};
TreeNode t[MaxSize];//定义一颗二叉树
2.二叉树的链式存储结构——二叉链表
typedef struct BiNode{
Elemtype data;
struct BiNode *lchild,*rchild;
}BiNode,*BiTree;
BiTree root=NULL; //定义一颗二叉树
3.二叉树的链式存储结构——三叉链表
typedef struct BiNode{
Elemtype data;
struct BiNode *lchild,*parent,*rchild;
}BiNode,*BiTree;
BiTree root=NULL; //定义一颗二叉树
4.1.2 二叉树的遍历
1.递归实现
先序遍历
void PerOrder(BiTree T){
if(T!=NULL){ //空二叉树
printf("%d\t",T->data); //访问根结点
PerOrder(T->lchild); //访问左子树
PerOrder(T->rchild); //访问右子树
}
}
中序遍历
void InOrder(BiTree T){
if(T!=NULL){ //空二叉树
InOrder(T->lchild); //访问左子树
printf("%d\t",T->data); //访问根结点
InOrder(T->rchild); //访问右子树
}
}
后序遍历
void PostOrder(BiTree T){
if(T!=NULL){ //空二叉树
PostOrder(T->lchild); //访问左子树
PostOrder(T->rchild); //访问右子树
printf("%d\t",T->data); //访问根结点
}
}
2.非递归实现
先序遍历
void PerOrderIterative(BiTree T){
SqStack s;
InitStack(&s);
//将根节点入栈
if(T != NULL) Push(&s,T)
while(!StackEmpty(&s)){
BiTree node=Pop(&s); //出栈并保存栈顶结点
printf("%d\t",node->data); //访问结点数据
//子结点入栈,右孩子先入栈,左孩子后入栈
if(node->rchild) push(&s,node->rchild);
if(node->lchild) push(&s,node->lchild);
}
DestoryStack(&s);
}
中序遍历
void InOrderIterative(BiTree T){
SqStaack s;
InitStack(&s);
if(T!=NULL) BiTree* currentNode=T; //维护一个当前结点指针
while(currentNode || !StackEmpty(&s)){ //当前结点非空或栈非空
//当前结点非空,沿着左子树方向入栈
while(currentNode){
Push(&s,currentNode);
currentNode=currentNode->lchild;
}
//此时访问到了最左
currentNode=Pop(&s); //出栈,并保存栈顶结点
printf("%d\t",currentNode->data); //访问结点数据
currentNode=currentNode->right; //将当前结点设为左子树
}
DestoryStack(&s);
}
后序遍历
void PostOrderIterative(BiTree T){
SqStack s;
InitStack(&s);
if(T != NULL){
BiTree *currentNode = T;
BiTree *visitedNode = T;
}
while(currentNode || !StackEmpty(&s)){
while(currentNode){
Push(currentNode);
currentNode=currentNode->lchild;
}
currentNode=GetHead(&s);
if(currentNode->rchild && currentNode->rchild!= visitedNode){
currentNode=currentNode->right;
}
else{
printf("%d",currentNode->data);
visitedNode=currentNode;
currentNode=NULL;
Pop(&s);
}
}
}
层次遍历
借助队列实现
void LevelOrder(BiTree T){
//初始化队列
SqQUeue q;
InitQueue(&q);
//将根结点入队
if(T != NULL) EnQueue(&q,T);
while(QueueLength>0){
//取队头结点
BiTree front=GetHead(&q);
printf("%d\t",front->data);
//如果存在左孩子,则将左孩子入队
if (front->lchild != NULL)
QueuePush(&q, front->lchild);
//如果存在右孩子,则将右孩子入队
if (front->rchild != NULL)
QueuePush(&q, front->rchild);
//将结点出队
DeQueue(&q);
}
DestoryQueue(&q);
}
4.1.3 线索二叉树
4.2 树
4.2.1 树的存储结构
4.3 树与二叉树的应用
4.3.1 哈夫曼树和哈夫曼编码
第五章.图
5.1 图的存储结构
5.1.1 邻接矩阵
5.1.2 邻接表
5.2 图的遍历
5.2.1 深度优先搜索(BFS)
5.2.2 广度优先搜索(DFS)
5.3图的应用
5.3.1 最小代价生成树
1.Prim算法
2.Kruskal算法
5.3.2 最短路径
1.Dijkstra算法
2.Floyd算法
5.3.3 拓扑排序
5.3.4 关键路径
第六章.查找
6.2 顺序查找法
6.3 折半查找法
6.4 分块查找法
6.5 二叉排序树
6.6 平衡二叉树
第七章.排序
7.1 直接插入排序
void INSERT_SORT(int* arr,int len) {
for(int i = 1; i < len; i++){
int j = i - 1;
int key = arr[i];
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
7.2 折半插入排序
void INSERT_SORT2(int arr[], int len) {
for (int i = 1; i < len; i++) {
int low = 0,height=i-1;
int key = arr[i];
while (low <= height) {
int mid = (low + height) / 2;
if (arr[mid] > key) height = mid - 1;
else low = mid + 1;
}
for (int j = i - 1; j >= height + 1; j--) arr[j + 1] = arr[j];
arr[height+1] = key;
}
}
7.3 希尔排序
void SHELL_SORT(int arr[], int len) {
int num = 4;
while (num >= 1) {
for (int i = num; i < len; i++) {
int key = arr[i];
int j = i - num;
while (j >= 0 && arr[j] > key) {
arr[j + num] = arr[j];
j -= num;
}
arr[j + num] = key;
}
num /= 2;
}
}
7.4 冒泡排序
void BUBBLE_SORT(int arr[],int len) {
int flag = 1;
for (int i = 0; i < len&&flag==1; i++) {
flag = 0;
for (int j = 0; j < len - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
flag = 1;
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
7.5 快速排序
int PivotLoc(int arr[], int low, int height) {
int pivotkey = arr[low];
while (low < height) {
while (low < height && arr[height] >= pivotkey)height--;
arr[low] = arr[height];
while (low < height && arr[low] <= pivotkey)low++;
arr[height] = arr[low];
}
arr[low] = pivotkey;
return low;
}
void QUICK_SORT(int arr[],int low,int height) {
if (low < height) {
int pivotloc = PivotLoc(arr,low,height);
QUICK_SORT(arr,low,pivotloc);
QUICK_SORT(arr,pivotloc+1,height);
}
}
7.6 简单选择排序
7.7 堆排序
7.8 二路归并排序
void MERGE(int* arr, int p, int q, int r) {
int n1 = q - p+1;
int n2 = r - q;
int* arr1 = (int*)malloc(sizeof(int) * n1);
int* arr2 = (int*)malloc(sizeof(int) * n2);
for (int i = 0; i < n1; i++) arr1[i] = arr[p + i];
for (int i = 0; i < n2; i++) arr2[i] = arr[q + i + 1];
int i = 0, j = 0, k = p;
while (i < n1 && j < n2) {
if (arr1[i] < arr2[j]) arr[k++] = arr1[i++];
else arr[k++] = arr2[j++];
}
while (i < n1) arr[k++] = arr1[i++];
while (j < n2) arr[k++] = arr2[j++];
free(arr1);
free(arr2);
}
void MERGE_SORT(int* arr, int p, int r) {
if (p < r) {
int q = (p + r) / 2;
MERGE_SORT(arr, p, q);
MERGE_SORT(arr, q + 1, r);
MERGE(arr, p, q, r);
}
else return;
}