文章目录
- 1.快速排序
- 2.划分思想
- 3.二路归并
- 4.链表
- 1>使用计数器统计链表的长度
- 2>按照关键字条件查找+删除
- 3>按照关键字条件查找+插入
- 5.头插法(原地逆置)
- 6.尾插法(保持原序)
- 7.二叉树
- 1>前/中/后序遍历
- 2>层序遍历
- 3>求树的高度
- 4>求树的宽度
- 5->求WPL(带权路径长度)
- 6->判定二叉排序树
- 7->判定二叉树是否平衡
- 8->判定完全二叉树
1.快速排序
使用条件:必须是”顺序表“,即“数组”。乱序
快排优势:时间复杂度低,代码简洁。
int huafen (int A[],int L,int R){
int mid = A[L];//选择最左边的作为枢轴
while(L<R){
while(A[R]>=mid && L<R) R--;
A[L]=A[R];
while(A[L]<=mid && L<R) L++;
A[R]=A[L];
}
A[L]=mid;
return L;//返回划分的中点位置
}
void Qsort(int A[],int L,int R){
if(L>=R) return;//递归终止
int M=huafen(A,L,R);
Qsort(A,L,M-1);//左半部分快排
Qsort(A,M+1,R);//右半部分快排
}
11分
int huafen (int A[],int L,int R){
int mid = A[L];//选择最左边的作为枢轴
while(L<R){
while(A[R]>=mid && L<R) R--;
A[L]=A[R];
while(A[L]<=mid && L<R) L++;
A[R]=A[L];
}
A[L]=mid;
return L;//返回划分的中点位置
}
void Qsort(int A[],int L,int R){
if(L>=R) return;//递归终止
int M=huafen(A,L,R);
Qsort(A,L,M-1);//左半部分快排
Qsort(A,M+1,R);//右半部分快排
}
int func(int A[],int N,int B[],int M){
int C[N+M];
for(int i=0;i<N;i++){
C[i]=A[i];
}
for(int i=0;i<M;i++){
C[i+N]=B[i];
}
Qsort(C,0,N+M-1);//对数组使用快排
return C[(N+M-1)/2];//返回中位数
}
为什么空间复杂度不是log2 (n+m)?
因为我们定义的C数组大于log 2(n+m)。
12分
int Merge(int A[],int n,int B[],int m,int C[]){
int i=0,j=0,k=0;
while(i<n && j<m){
if(A[i]<=B[j]) C[k++]=A[i++];
else C[k++]=B[j++];
}
while(i<n) C[k++]=A[i++];
while(j<m) C[k++]=B[j++];
return 1;
}
int func(int A[],int n,int B[],int m){
int C[n+m];
Merge(A,n,B,m,C);
return C[(n+m)/2];
}
Merge 操作的空间复杂度为O(n)。
一趟Merge(归并)的时间复杂度为O(n)。
int huafen (int A[],int L,int R){
int mid = A[L];//选择最左边的作为枢轴
while(L<R){
while(A[R]>=mid && L<R) R--;
A[L]=A[R];
while(A[L]<=mid && L<R) L++;
A[R]=A[L];
}
A[L]=mid;
return L;//返回划分的中点位置
}
void Qsort(int A[],int L,int R){
if(L>=R) return;//递归终止
int M=huafen(A,L,R);
Qsort(A,L,M-1);//左半部分快排
Qsort(A,M+1,R);//右半部分快排
}
int func(int A[],int N){
Qsort(A,0,N-1);
int n=A[N/2];
int count=0;
//for(int i=0;i<N;i++){
// if(n==A[i]){
// count++;
// }
//}//以下是王道的答案;
for(int i=N/2;i>=0;i--){
if(n==A[i]){
count++;
}
}
for(int i=N/2-1;i<N;i++){
if(n==A[i]){
count++;
}
}
if(count>N/2){
return n;
}else{
return -1;
}
}
时间复杂度和空间复杂度就是快速排序的时间复杂度和空间复杂度。
int huafen (int A[],int L,int R){
int mid = A[L];//选择最左边的作为枢轴
while(L<R){
while(A[R]>=mid && L<R) R--;
A[L]=A[R];
while(A[L]<=mid && L<R) L++;
A[R]=A[L];
}
A[L]=mid;
return L;//返回划分的中点位置
}
void Qsort(int A[],int L,int R){
if(L>=R) return;//递归终止
int M=huafen(A,L,R);
Qsort(A,L,M-1);//左半部分快排
Qsort(A,M+1,R);//右半部分快排
}
int func(int A[],int n){
Qsort(A,0,n-1);
int m =-1;
for(int i=0;i<n;i++){
if(A[i]>0){
m = i;
break;
}
}
if(m == -1) return 1;//如果m等于-1说明,数组A全都是小于0
if(A[m] != 1) return 1;//如果能走到下一条语句,说明A[m]等于1,无须再判断
for(m=m+1;m<n;m++){
if(A[m]-A[m-1]>1){
return A[m-1]+1;//作差后大于1,则返回小的加1
}
}
return A[n-1]+1;//返回最后一个值加1,此时数组A所有元素均是紧挨着的
}
2.划分思想
第K小(或第K大)可理解为,排好序之后的位置,因为数组排好序之后位置与数组下标是有对应关系的;
int huafen (A[],int L,int R){
int mid=A[0];//选择枢轴
while(L<R){
while(A[R]>=mid && L<R) R--;
A[L]=A[R];
while(A[L]<=mid && L<R) L++;
A[R]=A[L];
}
A[L]=mid;//划分位置的值
return L;//返回划分的位置
}
int func(int A[],int n,int K){//找到第K小的元素
int L=0,R=n-1,M=0;
while(1){
M = huafen(A,L,R);
if(M==K-1) break;
else if(M > K-1) R=M-1;
else if(M < K-1) L=M+1;
}
return A[K-1];
}
int huafen (A[],int L,int R){
int mid=A[0];//选择枢轴
while(L<R){
while(A[R]>=mid && L<R) R--;
A[L]=A[R];
while(A[L]<=mid && L<R) L++;
A[R]=A[L];
}
A[L]=mid;//划分位置的值
return L;//返回划分的位置
}
int func(int A[],int n,int K){//找到第K小的元素
int L=1,R=n,M=0;
while(1){
M = huafen(A,L,R);
if(M==K) break;
else if(M > K) R=M-1;
else if(M < K) L=M+1;
}
return A[K];
}
最优解
int huafen (A[],int L,int R){
int mid=A[0];//选择枢轴
while(L<R){
while(A[R]>=mid && L<R) R--;
A[L]=A[R];
while(A[L]<=mid && L<R) L++;
A[R]=A[L];
}
A[L]=mid;//划分位置的值
return L;//返回划分的位置
}
int func(int A[],int n){//找到第K小的元素
int K=n/2;
int L=0,R=n-1,M=0;
while(1){
M = huafen(A,L,R);
if(M==K-1) break;
else if(M > K-1) R=M-1;
else if(M < K-1) L=M+1;
}
return A[K-1];
}
3.二路归并
int Merge(int A[],int n,int B[],int m,int C[]){
int i=0,j=0,k=0;
while(i<n && j<m){
if(A[i]<=B[j]) C[k++]=A[i++];
else C[k++]=B[j++];
}
while(i<n) C[k++]=A[i++];
while(j<m) C[k++]=B[j++];
return 1;
}
Merge 操作的空间复杂度为O(n)。
一趟Merge(归并)的时间复杂度为O(n)。
二路归并中,共需要log2n趟,故时间复杂度为O(nlog2n)
4.链表
1>使用计数器统计链表的长度
//定义单链表结点
typedef struct LNode{
int data;
struct LNode* next;
}LNode, *LinkList;
//求单链表长度
int listLen(LinkList L){
int length=0;
LNode *p=L->next;
while (p!=NULL){
length++;
p=p->next;
}
printf("链表的长度 = %d \n",length);
return length;
}
//返回单链表的中间结点
int findMidNode(LinkList L){
int length=0;
LNode *p=L->next;
while (p!=NULL){
length++;
p=p->next;
}
int count=0;//计数器
p= L->next;//让p指向头节点的下一个节点,(从头开始遍历)
while(p!=NULL){
if(count == lengtj/2) break;//找到中间结点,跳出循环
p=p->next;//指向下一个结点
}
p=p->next;
return p;
}
//求单链表长度
int listLen(LinkList L){
int length=0;
LNode *p=L->next;
while (p!=NULL){
length++;
p=p->next;
}
return length;
}
//返回指针类型
LinkNode *Find_1st_Common(LinkList str1,LinkList str2){
int len1=listLen(str1),len2=listLen(str2);
LinkNode *p,*q;
for(p=str1;len1>len2;len1--) //使 p 指向的链表与 q 指向的链表等长
p=p->next;
for(q=str2;len1<len2;len2--) //使 q 指向的链表与 p 指向的链表等长
q=q->next;
while(p->next!=NULL&&p->next!=q->next){//查找共同后缀起始点
p=p->next; //两个指针同步向后移动
q=q->next;
}
return p->next; //返回共同后缀的起始点
}
2>按照关键字条件查找+删除
//删除值为X的结点
int deletX(LinkList L,int x){
LNode *pre = L; //pre指向p的前驱节点
LNode *p =pre ->next;//指向pre的下一个结点
while(p!=NULL){
if(p->data==x){
LNode *q = p;//释放值为x的结点
pre->next = p->next;//删除节点,修改指针
free(q);
}else{
pre = p;//两个指针同时移动
p= p->next;
}
}
}
3>按照关键字条件查找+插入
void InsertX(LinkList L,int x){
LNode *pre = L;
LNode *p = pre->next;
while (p!=NULL){
if(p->data >x){
break;
}