一.顺序表和链表
1.顺序表
(1)定义并初始化
静态分配
cpp
#define MaxSize 10
typedef int ElemType;
typedef struct{
ElemType data[MaxSize];
int length;
}SqList;
void InitList(SqList &L){
L.length=0;
}
动态分配
cpp
#define InitSize 10
typedef struct{
ElemType *data;
int MaxSize,length;
}SqList;
(2)插入
cpp
bool ListInsert(SqList &L,ElemType elem,int i){
//在第i个位置插入元素elem
if(i<1 || i>L.length+1) return false;
if(L.length >= MaxSize) return false;//已经满了
for(int j=L.length;j>=i;j--){
L.data[j]=L.data[j-1];
}
L.data[i-1]=elem;
L.length+=1;
return true;
}
时间复杂度O(n)
(3)删除
cpp
bool ListDelete(SqList &L,ElemType &elem,int i){
//删除第i个元素并保留到elem中
if(i<1 || i>L.length) return false;
elem=L.data[i-1];
for(int j=i-1;j<L.length-1;j++){
L.data[j]=L.data[j+1];
}
L.length-=1;
return true;
}
时间复杂度O(n)
(4)按位查找
cpp
int GetElem(SqList L,int i){
return(L.data[i]);
}
时间复杂度O(1)
(5)按值查找
cpp
int LocateElem(SqList L,ElemType elem){
//查找值为elem的元素所在位置
for(int i=0;i<L.length;i++){
if(L.data[i]==elem){
return i+1;
}
}
return 0;//查找失败
}
时间复杂度O(n)
2.链表
(1)定义
cpp
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
(2)头插法
cpp
void list_head_insert(LinkList &L){
int elem;
LNode *s;//插入结点
L= (LinkList)malloc(sizeof (LNode));//头结点分配空间
L->next=NULL;
scanf("%d",&elem);
while(elem != '\n'){
s= (LinkList)malloc(sizeof (LNode));//插入结点分配空间
s->data=elem;
s->next=L->next;
L->next=s;
scanf("%d",&elem);
}
}
(3)尾插法
cpp
void list_hail_insert(LinkList &L){
LNode *s,*p;//p是尾指针
ElemType elem;
L= (LinkList)malloc(sizeof (LNode));
L->next=NULL;
p=L;//得等到给L分配空间后才能让p=L
scanf("%d",&elem);
while (elem!=9999){
s= (LinkList)malloc(sizeof (LNode));
s->data=elem;
s->next=p->next;
p->next=s;
p=s;
scanf("%d",&elem);
}
p->next=NULL;
}
(4)按位查找
cpp
LNode* GetElem(LinkList L,int i){
int j=0;
if(i<0) return NULL;
while (L && j<i){//结点不为空,且下标没达到i
L=L->next;
j++;
}
return L;
}
时间复杂度O(n)
(5)按值查找
cpp
LNode* LocateElem(LinkList L,ElemType x){
L=L->next;
while (L!=NULL && L->data!=x){
L=L->next;
}
return L;//返回结点指针
}
时间复杂度O(n)
(6)前插结点
cpp
void InsertPriorNode(LNode *p,ElemType elem){
//在结点p前面插入元素elem
LNode *s= (LinkList)malloc(sizeof (LNode));
s->next=p->next;
p->next=s;
s->data=p->data;
p->data=elem;
}
时间复杂度O(1)
(7)删除结点
cpp
void DeleteNode(LNode *p,ElemType &x){
//删除结点p
LNode *q=p->next;
p->data=q->data;
p->next=q->next;
free(q);
}
时间复杂度O(1)
3.双链表
(1)定义并初始化
cpp
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
void InitDLinkList(DLinkList &L){
L= (DLinkList)malloc(sizeof (DNode));
L->next=NULL;
L->prior=NULL;
}
(2)插入
cpp
bool InsertNextNode(DNode *p,DNode *s){
//在结点p后插入结点s
if(p==NULL || s==NULL){
return false;
}
s->next=p->next;
if(p->next!=NULL){//只有p有后继结点,才有prior指针
p->next->prior=s;
}
p->next=s;
s->prior=p;
return true;
}
(3)删除
cpp
bool DeleteNextNode(DNode *p){
//删除p的后继结点
if(p==NULL) return false;
DNode *q=p->next;
if(q==NULL) return false;//没有后继
p->next=q->next;
if(q->next!=NULL){//不能是最后一个结点
q->next->prior=p;
}
free(q);
return true;
}
(4)销毁
cpp
void DestroyList(DLinkList &L){
while (L->next!=NULL){
DeleteNextNode(L);
}
free(L);//释放头结点
L=NULL;//头指针指向NULL
}
4.循环链表
循环单链表
cpp
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
void InitList(LinkList &L){
L= (LinkList)malloc(sizeof (LNode));
L->next=L;
}
循环双链表
cpp
typedef struct LNode{
ElemType data;
struct LNode *next,*prior;
}LNode,*LinkList;
void InitList(LinkList &L){
L= (LinkList)malloc(sizeof (LNode));
L->next=L;
L->prior=L;
}
5.静态链表
cpp
#define MaxSize 10
typedef int ElemType;
typedef struct {
ElemType data;
int next;//下个元素的数组下标
}SLinkList[MaxSize];
二.栈和队列
1.栈
(1)定义并初始化
顺序栈
cpp
typedef struct {
ElemType data[MaxSize];
int top;
}SqStack;
void InitStack(SqStack &S){
S.top=-1;
}
链栈
cpp
typedef struct LNode{
ElemType data;
struct LNode *next;
}*LiStack;
(2)判空
cpp
bool StackEmpty(SqStack S){
if(S.top==-1){
return true;
} else{
return false;
}
}
(3)进栈
cpp
bool Push(SqStack &S,ElemType x){
if(S.top==MaxSize-1){//栈满
return false;
}
S.data[++S.top]=x;
return true;
}
(4)出栈
cpp
bool Pop(SqStack &S,ElemType &x){
if(S.top==-1){//栈空
return false;
}
x=S.data[S.top--];
return true;
}
(5)获取栈顶元素
cpp
bool GetTop(SqStack &S,ElemType &x){
if(S.top==-1){
return false;
}
x=S.data[S.top];
return true;
}
2.队列
2.1顺序队列
(1)定义并初始化
cpp
typedef struct {
ElemType data[MaxSize];
int front,rear;
}SqQueue;
void InitQueue(SqQueue &Q){
Q.front=Q.rear=0;
}
(2)判空
cpp
bool isEmpty(SqQueue Q){
if(Q.rear==Q.front){
return true;
} else{
return false;
}
}
(3)入队
cpp
bool EnQueue(SqQueue &Q,ElemType x){
if((Q.rear+1)%MaxSize==Q.front){//队满
return false;
}
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%MaxSize;//更新尾指针位置
return true;
}
(4)出队
cpp
bool DeQueue(SqQueue &Q,ElemType &x){
if(Q.rear==Q.front){//队空
return false;
}
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
}
2.2链式队列
(1)定义并初始化
cpp
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode;
typedef struct {
LNode *front,*rear;
}LinkQueue;
void InitQueue(LinkQueue &Q){
Q.front=Q.rear= (LNode*)malloc(sizeof (LNode));
Q.front->next=NULL;
}
(2)入队
带头结点
cpp
void EnQueue(LinkQueue &Q,ElemType x){
LNode *pnew= (LNode*)malloc(sizeof (LNode));
pnew->data=x;
pnew->next=NULL;//队尾元素指向NULL
Q.rear->next=pnew;
Q.rear=pnew;
}
不带头结点
cpp
void EnQueue(LinkQueue &Q,ElemType x){
LNode *pnew= (LNode*)malloc(sizeof (LNode));
pnew->data=x;
pnew->next=NULL;//队尾元素指向NULL
if(Q.front==NULL){
Q.front=pnew;//无头结点要修改front,rear指针
Q.rear=pnew;
}else {
Q.rear->next = pnew;
Q.rear = pnew;
}
}
(3)出队
带头结点
cpp
bool DeQueue(LinkQueue &Q,ElemType &x){
if(Q.rear==Q.front){//队空
return false;
}
LNode *q=Q.front->next;//拿到第一个结点,存入q
x=q->data;
Q.front->next=q->next;
if(Q.rear==q){
Q.rear=Q.front;//只剩一个结点时,防止rear没有指向的地方
}
free(q);
return true;
}
不带头结点
cpp
bool DeQueue(LinkQueue &Q,ElemType &x){
if(Q.rear==Q.front){//队空
return false;
}
LNode *p=Q.front;
x=p->data;
Q.front=p->next;//出队
if(Q.rear==p){
Q.front=NULL;//这是最后一个结点
Q.rear=NULL;
}
free(p);
return true;
}
3.栈的应用
(1)括号匹配
cpp
#include <stdio.h>
#define MaxSize 10
typedef char ElemType;
typedef struct {
ElemType data[MaxSize];
int top;
}SqStack;
void InitStack(SqStack &S){
S.top=-1;
}
bool StackEmpty(SqStack S){
if(S.top==-1){
return true;
} else{
return false;
}
}
bool Push(SqStack &S,ElemType x){
if(S.top==MaxSize-1){
return false;
}
S.data[++S.top]=x;
return true;
}
bool Pop(SqStack &S,ElemType &x){
if(StackEmpty(S)){
return false;
}
x=S.data[S.top--];
return true;
}
bool BracketCheck(char str[],int length){
SqStack S;
InitStack(S);
for(int i=0;i<length;i++){
if(str[i]=='(' || str[i]=='[' || str[i]=='{'){
Push(S,str[i]);
} else{
if(StackEmpty(S)){
return false;
}
char TopElem;
Pop(S,TopElem);
if(TopElem=='(' && str[i]!=')'){
return false;
}
if(TopElem=='[' && str[i]!=']'){
return false;
}
if(TopElem=='{' && str[i]!='}'){
return false;
}
}
}
return StackEmpty(S);
}
int main(){
char str[MaxSize];
int i=0;
while(i<MaxSize && (str[i]=getchar())!='\n'){
i++;
}
str[i]='\0';//字符串结束符
bool ret= BracketCheck(str,i);
if(ret){
printf("Success\n");
} else{
printf("Fail\n");
}
return 0;
}
(2)递归
cpp
int Fib(n){//斐波那契数列实现
if(n==0)
return 0;//边界条件
else if(n==1)
return 1;//边界条件
else
return Fib(n-1)+Fib(n-2);//递归表达式
}
三.串
1.基础操作
(1)定义
顺序存储
cpp
//静态数组
#define MaxLen 10
typedef struct {
char ch[MaxLen];
int length;
}SString;
//动态数组
typedef struct {
char *ch;
int length;
}HString;
HString S;
S.ch=(char*)malloc(sizeof (char));
S.length=0;
链式存储
cpp
typedef struct StringNode{
char ch[4];//每个结点存4个字符
struct StringNode *next;
}StringNode,*String;
(2)求子串
cpp
//从主串S的pos位置开始取长度为len的子串
bool SubString(SString &Sub,SString S,int pos,int len){
if(pos+len-1>S.length){
return false;
}
for(int i=pos;i<pos+len;i++){
Sub.ch[i-pos+1]=S.ch[i];//从下标1开始存储
}
Sub.length=len;
return true;
}
(3)比较
cpp
int StrCompany(SString S,SString T){
for(int i=1;i<=S.length && i<=T.length;i++){
if(S.ch[i]!=T.ch[i]){
return S.ch[i]-T.ch[i];//不同则返回差值
}
}
return S.length-T.length;//前面元素均相同
}
(4)定位
cpp
//在S中寻找与T相同的子串
int Index(SString S,SString T){
int i;
SString Sub;
while(i<S.length-T.length+1){
SubString(Sub,S,i,T.length);
if(StrCompany(Sub,T)!=0){
i++;//不匹配,i后移
} else{
return i;//找到了
}
}
return 0;//没找到
}
2.朴素模式匹配算法
cpp
int Index(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){//找到了(T全部匹配成功)
return i-T.length;
} else {//没找到
return 0;
}
}
时间复杂度O(mn)
3.KMP算法
cpp
int Index_KMP(SString S,SString T,int next[]){
int i=1,j=1;
while(i<=S.length && j<=T.length){
if(S.ch[i]==T.ch[j]){
i++;
j++;
} else{
j=next[j];//主串指针i不回溯,j按照next数组回溯
}
}
if(j>T.length){//找到了(T全部匹配成功)
return i-T.length;
} else {//没找到
return 0;
}
}
时间复杂度O(m+n)
4.求next数组
cpp
void get_next(SString S,int next[]){
int i=1,j=0;
next[1]=0;
while(i<S.length){
if(j==0 || S.ch[i]==S.ch[j]){
next[i++]=j++;
} else{
j=next[j];
}
}
}
时间复杂度O(m)
四.树与二叉树
1.构建二叉树
cpp
typedef char ElemType;
typedef struct BiTNode{
ElemType c;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
typedef struct tag{//辅助队列
BiTNode *p;
struct tag *pnext;
}tag_t,*ptag_t;
int main(){
BiTree T=NULL,pnew;//T指向树根,pnew用来指向新申请的结点
//listpnew表示新入队结点,pcur指向队列中每一层的根节点
ptag_t phead=NULL,ptail=NULL,listpnew=NULL,pcur=NULL;
char c;
while (scanf("%c",&c)){
if(c=='\n'){
break;
}
pnew= (BiTree)calloc(1,sizeof (BiTNode));
pnew->c=c;
listpnew= (ptag_t)calloc(1, sizeof (tag_t));
listpnew->p=pnew;
//如果是树的第一个结点
if(T==NULL){
T=pnew;
phead=listpnew;
ptail=listpnew;
pcur=listpnew;
} else{
ptail->pnext=listpnew;
ptail=listpnew;
if(pcur->p->lchild==NULL){
pcur->p->lchild=pnew;
} else if(pcur->p->rchild==NULL){
pcur->p->rchild=pnew;
pcur=pcur->pnext;//当前结点左右孩子都有了
}
}
}
}
2.遍历二叉树
(1)先序,中序,后序遍历
cpp
//前序遍历,也叫先序遍历,也是深度优先遍历
void PreOrder(BiTree p){
if(p!=NULL){
printf("%c",p->c);
PreOrder(p->lchild);//打印左子树
PreOrder(p->rchild);//打印右子树
}
}
//中序遍历
void InOrder(BiTree p){
if(p!=NULL){
InOrder(p->lchild);//打印左子树
printf("%c",p->c);
InOrder(p->rchild);//打印右子树
}
}
//后序遍历
void PostOrder(BiTree p){
if(p!=NULL){
InOrder(p->lchild);//打印左子树
InOrder(p->rchild);//打印右子树
printf("%c",p->c);
}
}
(2)层序遍历
cpp
void LevelOrder(BiTree T){
LinkQueue Q;//链式队列
InitQueue Q;
EnQueue(Q,T);
BiTree p;//存储出队元素
while(!IsEmpty(Q)){
DeQueue(Q,p);
putchar(p->c);
if(p->lchild!=NULL){
EnQueue(Q,p->lchild);
}
if(p->rchild!=NULL){
EnQueue(Q,p->rchild);
}
}
}
六.查找
1.顺序查找(Search_Seq)
cpp
typedef struct {
ElemType *elem;//动态分配顺序表
int TableLen;//长度
}SSTable;
void Init_Seq(SSTable &ST,int len){
ST.TableLen=len+1;//多一个位置存哨兵
ST.elem= (ElemType*)malloc(ST.TableLen*(sizeof (SSTable)));
}
int Search_Seq(SSTable ST,ElemType x){
int i;
ST.elem[0]=x;//哨兵
for(i=ST.TableLen;ST.elem[i]!=x;i--);//从后往前查找
return i;//找不到返回0
}
2.折半查找(BinarySearch)
cpp
typedef struct {
ElemType *elem;//动态分配顺序表
int TableLen;
}SSTable;
void Init_Seq(SSTable &ST,int len){
ST.TableLen=len;
ST.elem= (ElemType*)malloc(ST.TableLen*(sizeof (SSTable)));
}
//前提是原数组有序
int BinarySearch(SSTable ST,ElemType x){
int low=0,high=ST.TableLen-1;
int mid;
while (low<=high){
mid=(low+high)/2;//放在循环中
if(ST.elem[mid]==x){
return mid;//找到了
} else if(ST.elem[mid]>x){
high=mid-1;
} else{
low=high+1;
}
}
return -1;//没找到
}
3.二叉排序树(BST)
(1)定义
cpp
typedef struct BSTNode{
ElemType key;
struct BSTNode *lchild,*rchild;
}BSTNode,*BiTree;
(2)构造
非递归
cpp
int BST_Insert(BiTree &T,ElemType k){
BiTree TreeNew= (BiTree)calloc(1,sizeof (BSTNode));
TreeNew->key=k;
if(T==NULL){
T=TreeNew;
return 1;
}
BiTree p=T,parent;//p用来查找树
//p为NULL的时候,就是k存储的位置
while(p){
parent=p;//parent用来存p的父亲
if(k>p->key){
p=p->rchild;
} else if(k<p->key){
p=p->lchild;
} else{
return 0;//相等的元素不可以放入查找树,考研不考
}
}
//接下来要判断放到父亲的左边还是右边
if(k>parent->key){
parent->rchild=TreeNew;
}else{
parent->lchild=TreeNew;
}
return 1;
}
递归
cpp
int Insert(BiTree &T,ElemType key){
if(T==NULL){//注意这里用calloc分配空间
T= (BiTree)calloc(1,sizeof (BSTNode));
T->key=key;
return 1;//插入成功
} else if(key==T->key){
return 0;//插入失败
} else if(key<T->key){
return Insert(T->lchild,key);
} else {
return Insert(T->rchild,key);
}
}
void CreatBST(BiTree &T,int str[],int len){
for(int i=0;i<len;i++){
Insert(T,str[i]);
}
}
空间复杂度O(h)
(3)查找结点
非递归
cpp
BSTNode* BST_Search(BiTree T,ElemType key){
while (T!=NULL && T->key!=key){
if(T->key>key) T=T->lchild;
else T=T->rchild;
}
return T;
}
空间复杂度O(1)
递归
cpp
BSTNode* BST_Search(BiTree T,ElemType key){
if(T==NULL){
return NULL;
}
if(T->key==key){
return T;
} else if(T->key<key){
return BST_Search(T->rchild,key);
} else{
return BST_Search(T->rchild,key);
}
}
空间复杂度O(n)
(4)删除结点
cpp
void DeleteNode(BiTree &root,ElemType key){
if(root==NULL){//空树
return;
}
if(root->key>key){
DeleteNode(root->lchild,key);
} else if(root->key<key){
DeleteNode(root->rchild,key);
} else{
BiTree TreeNode;
if(root->lchild==NULL){//左子树为空,右子树直接顶上去
TreeNode=root;
root=root->rchild;
free(TreeNode);
} else if(root->rchild==NULL){//右子树为空,右子树直接顶上去
TreeNode=root;
root=root->lchild;
free(TreeNode);
} else{
//删除选取左子树最大数据或右子树最小数据
//查找左子树最右边结点或右子树最左结点替换
TreeNode=root->lchild;
while (TreeNode->rchild!=NULL){
TreeNode=TreeNode->rchild;
}
root->key=TreeNode->key;//将tempNode对应的值替换到要删除的值上面
DeleteNode(root->lchild,TreeNode->key);//删除root左子树中被替代的结点
}
}
}
七.排序
1.插入排序
(1)直接插入排序
不带哨兵
cpp
void InsertSort(int A[],int n){
int i,j,interval;
for(i=1;i<n;i++){//i代表有序数的个数
interval=A[i];//准备插入的元素
for(j=i-1;j>=0&&A[j]>interval;j--){
A[j+1]=A[j];
}
A[j+1]=interval;//放到插入位置
}
}
带哨兵
cpp
void InsertSort(int A[],int n){
int i,j;
for(i=2;i<=n;i++){//将A[2]到A[n]依次插入
A[0]=A[i];
for(j=i-1;A[j]>A[0];j--){
A[j+1]=A[j];
}
A[j+1]=A[0];//放到插入位置
}
}
2.交换排序
(1)冒泡排序
cpp
void swap(ElemType &a,ElemType &b){
ElemType temp;
temp=a;
a=b;
b=temp;
}
void BubbleSort(int A[],int n){
bool flag;
for(int i=0;i<n-1;i++){
flag= false;//每轮循环判断是否有交换
for(int j=n-1;j>i;j--){
if(A[j]<A[j-1]){
swap(A[j],A[j-1]);
flag= true;//有交换
}
}
if(!flag){
return;//原本就是有序的,直接返回,优化时间复杂度
}
}
}
BubbleSort(ST.elem,n);//传入顺序表元素数组
(2)快速排序
cpp
int Partition(int A[],int low,int high){
int pivot=A[low];
if (low<high){
//找到比枢纽元素小的
while(low<high && A[high]>=pivot) high--;
A[low]=A[high];
//找到比枢纽元素大的
while (low<high && A[low]<=pivot) low++;
A[high]=A[low];
}
A[low]=pivot;//枢纽元素放到最终位置
return low;
}
void QuickSort(int A[],int low,int high){
if(low<high){
int pivotpos= Partition(A,low,high);//划分
QuickSort(A,low,pivotpos-1);
QuickSort(A,pivotpos+1,high);
}
}
3.选择排序
(1)简单选择排序
cpp
void SelectSort(int A[],int n){
for(int i=0;i<n-1;i++){//进行n-1趟
int min=i;//记录最小元素位置
for(int j=i+1;j<n;j++){
if(A[j]<A[min]) min=j;
}
if(min!=i) swap(A[j],A[min]);//找到了更小的元素
}
}