第二章顺序表
顺序表基础操作
#define MaxSize 50
typedef struct{
int data[MaxSize];
int length;
}SqList;
void InitList(SqList &L){
for(int i=0;i<MaxSize;i++){
L.data[i]=0;
}
L.length=0;
}
1 从顺序表中删除具有最小值的元素(假设唯一),并由函数返回被删除的元素,空出的位置由最后一个元素填补,若线性表为空,返回错误信息!
bool Delete_Min(SqList &L,int &value){
if(L.length==0){
return false;
}
value=L.data[0];
int min_pos=0;
for(int i=1;i<L.length;i++){
if(L.data[i]<value){
value=L.data[i];
min_pos=i;
}
}
L.data[min_pos]=L.data[L.length-1];
L.length--;
return true;
}
2 将顺序表逆置,要求空间复杂度为O(1)
void Reverse(SqList &L){
int temp;
for(int i=0;i<L.length/2;i++){
temp=L.data[i];
L.data[i]=L.data[L.length-i-1];
L.data[L.length-i-1]=temp;
}
}
3 删除顺序表中等于x的元素,要求时间复杂度O(n),空间复杂度O(1)
void Delete_x(SqList &L,int x){
int i,k;
i=0,k=0;
while(i<L.length){
if(L.data[i]==x){
k++;
}
else{
L.data[i-k]=L.data[i];
}
i++;
}
L.length=L.length-k;
}
4 删除有序顺序表中s到t中间的元素,要求s<t,显示错误信息(s和t也被删除了)
bool Delete_s_t(SqList &L,int s,int t){
int i,j;
if(s>=t||L.length==0){
return false;
}
for(i=0;i<L.length&&L.data[i]<s;i++);
if(i>L.length){
return false;
}
for(j=i;j<L.length&&L.data[j]<=t;j++);
for(;j<L.length;i++,j++){
L.data[i]=L.data[j];
}
L.length=i;
return true;
}
5 删除顺序表s到t中间的元素,要s<t,显示错误信息(s和t也被删除了)
bool Delete_s_t2(SqList &L,int s,int t){
if(L.length==0||s>=t){
return false;
}
int i,k=0;
for(i=0;i<L.length;i++){
if(L.data[i]>=s&&L.data[i]<=t){
k++;
}
else{
L.data[i-k]=L.data[i];
}
}
L.length=L.length-k;
return true;
}
6 删除有序顺序表中其值重复的元素,使得表中所有元素值不同
bool Delete_same(SqList &L){
if(L.length==0){
return false;
}
int i,j;
for(i=0,j=1;j<L.length;j++){
if(L.data[i]!=L.data[j]){
i++;
L.data[i]=L.data[j];
}
}
L.length=i+1;
return true;
}
如果是无序表
关键之处在于利用散列表的冲突来判断元素是否存在重复。于是解决散列表冲突的方式只能用拉链法,不能用开放地址法。散列表有数组和多个链表组成。数组里存储的是对应单个链表的首地址,链表中数据域用存储同义词。通过散列函数找到对应位置,继而判断是否存在相同元素。
!7 将两个有序顺序表合并成一个新的有序顺序表
bool Merge(SqList A,SqList B,SqList &M){
if(A.length+B.length>MaxSize){
return false;
}
int i=0,j=0,k=0;
while(i<A.length&&j<B.length){
if(A.data[i]<=B.data[j]){
M.data[k++]=A.data[i++];
}
else{
M.data[k++]=B.data[j++];
}
}
while(i<A.length){
M.data[k++]=A.data[i++];
}
while(j<B.length){
M.data[k++]=B.data[j++];
}
M.length=k;
return true;
}
8 将一个顺序表中的前m个元素和后n个元素进行整体互换,也就是将后面n个元素放在m个元素前面(思想:先整体逆置,然后将前n个元素再逆置,后m个元素再逆置)
void Reverse(SqList &L,int left,int right){
if(left>=right||right>MaxSize){
return;
}
int mid=(left+right)/2;
for(int i=0;i<=mid-left;i++){
int temp=L.data[i+left];
L.data[i+left]=L.data[right-i];
L.data[right-i]=temp;
}
}
void Change(SqList &L,int m,int n){
Reverse(L,0,m+n-1);
Reverse(L,0,n-1);
Reverse(L,n,m+n-1);
}
13 给定一个含有n个整数的数组,设计时间上尽可能高效的算法,找出数组中没有出现的最小正整数
空间换时间,采用标记数组B[n]记录A中是否出现了1~n中的正整数,B[0]对应1,B[n-1]对应n; n个整数,返回的值可能是1-n+1,小于0和大于n的值可以不采取任何操作
int findMissMin(int A[],int n){
int B[n+1]={0};
int i;
for(i=0;i<n;i++){
if(A[i]>0&&A[i]<=n){
B[A[i]-1]=1;
}
}
for(i=0;i<n;i++){
if(B[i]==0)
break;
}
return i+1;
}
第二章链表
链表基础操作
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
LinkList ListHeadInsert(LinkList &L){
int x;
LNode *s;
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
cout<<"输入一个整数:";
cin>>x;
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s;
cout<<"输入一个整数:";
cin>>x;
}
return L;
}
void printLinkList(LinkList L){
LNode *p;
p=L->next;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
1 设计递归方法,实现不带头结点的单链表中所有值为x的元素
void delete_x(LinkList &L,int x){
LNode *p;
if(L==NULL){
return;
}
if(L->data==x){
p=L;
L=L->next;
free(p);
delete_x(L,x);
}
else{
delete_x(L->next,x);
}
}
2 在带头结点的单链表中,删除所有值为x的结点
void delete_x1(LinkList &L,int x){
LNode *pre=L,*p=L->next,*q;
while(p!=NULL){
if(p->data==x){
q=p;
p=p->next;
pre->next=p;
free(q);
}
else{
pre=p;
p=p->next;
}
}
}
void delete_x2(LinkList &L,int x){
LNode *p=L->next,*r=L,*q;
while(p!=NULL){
if(p->data!=x){
r->next=p;
r=p;
p=p->next;
}
else{
q=p;
p=p->next;
free(q);
}
}
}
3 递归实现链表逆置输出
void Reverse_Print(LinkList L){
if(L->next!=NULL){
Reverse_Print(L->next);
}
if(L!=NULL){
cout<<L->data<<" ";
}
}
void R_print1(LinkList L){
if(L!=NULL){
Reverse_Print(L->next);
}
}
4 从一个带头结点的单链表中删除元素值最小的结点(假设最小值结点唯一)
void delete_min(LinkList &L){
LNode *pre=L,*p=L->next;
LNode *minpre=pre,*minp=p;
while(p!=NULL){
if(p->data < minp->data){
minp=p;
minpre=pre;
}
pre=p;
p=p->next;
}
minpre->next=minp->next;
free(minp);
}
5 编写算法将带有头结点的链表就地逆置,(就地:空间复杂度O(1) )
注意下面两种方法的函数类型,一个是直接对原链表操作,一个是对复制品操作然后返回一个新链表
void Reverse1(LinkList &L){
LNode *r,*p;
p=L->next;
L->next=NULL;
while(p!=NULL){
r=p->next;
p->next=L->next;
L->next=p;
p=r;
}
}
LinkList Reverse2(LinkList L){
LNode *pre,*p=L->next,*r=p->next;
p->next=NULL;
while(r!=NULL){
pre=p;
p=r;
r=r->next;
p->next=pre;
}
L->next=p;
return L;
}
6 有一个带头结点的单链表,设计算法使其递增有序
void list_Sort(LinkList &L){
LNode *pre,*p=L->next,*r=p->next;
p->next=NULL;
p=r;
while(p!=NULL){
r=r->next;
pre=L;
while(pre->next!=NULL && pre->next->data < p->data){
pre=pre->next;
}
p->next=pre->next;
pre->next=p;
p=r;
}
}
7 在一个带头结点的单链表中元素无序,要求删除介于给定两个值中间的所有结点(和1对比)
void delete_s_t(LinkList &L,int s,int t){
LNode *pre=L,*p=L->next,*q;
while(p!=NULL){
if(p->data>s && p->data<t){
pre->next=p->next;
q=p;
p=p->next;
free(q);
}else{
pre=p;
p=p->next;
}
}
}
8 给定两个单链表,编写算法找出两个结点的公共结点
思想: 理解公共结点,若两个链表有公共结点,则公共结点之后的所有结点都重合,从尾结点向前都相同;由于两个链表长度不一样(假设两个链表长度之差k),我们先在长链表遍历k个结点(保证后面能同时到达尾结点,前面k个结点肯定没有公共结点),然后对两个链表共同遍历,第一个相同的结点就是公共结点
int list_Length(LinkList L){
int i=0;
LNode *p=L->next;
while(p!=NULL){
i++;
p=p->next;
}
return i;
}
LNode* search_Common(LinkList A,LinkList B){
int len1=list_Length(A);
int len2=list_Length(B);
LNode *longList,*shortList;
int dist;
if(len1>len2){
longList=A->next;
shortList=B->next;
dist=len1-len2;
}else{
longList=B->next;
shortList=A->next;
dist=len2-len1;
}
while(dist--){
longList=longList->next;
}
while(longList!=NULL){
if(longList==shortList){
return longList;
}
longList=longList->next;
shortList=shortList->next;
}
return NULL;
}
int main(){
LinkList A;
ListHeadInsert(A);
printLinkList(A);
LNode *p=A->next;
int dist=4;
while(dist--){
p=p->next;
}
cout<<"p->data="<<p->data<<endl;
LinkList B;
B=(LinkList)malloc(sizeof(LNode *));
B->next=NULL;
B->next=p;
cout<<"B->next->data="<<B->next->data<<endl;
printLinkList(B);
LNode *common = search_Common(A,B);
cout<<"共同结点:"<<common->data<<endl;
return 0;
}
9 给定一个带表头结点的单链表,设L为头指针,要求按递增次序输出单链表中各结点中的数据,并释放结点所占的存储空间(不允许使用数组作为辅助空间)
void min_delete(LinkList &L){
LNode *pre,*p;
LNode *u;
while(L->next!=NULL){
pre=L;
p=L->next;
while(p->next!=NULL){
if(pre->next->data > p->next->data){
pre=p;
}
p=p->next;
}
cout<<pre->next->data<<endl;
u=pre->next;
pre->next=u->next;
free(u);
}
free(L);
}
10 将一个带头结点的单链表A分解为两个带头结点的单链表A和B,使得A中含有原表中位序为奇数的元素,B中含有原表中位序为偶数的元素结点,且保持相对位置不变(尾插法)
LinkList divide_List(LinkList &A){
LNode *B;
B=(LinkList)malloc(sizeof(LNode *));
B->next=NULL;
int i=0;
LNode *rb=B,*ra=A;
LNode *p=A->next;
A->next=NULL;
while(p!=NULL){
i++;
if(i%2!=0){
ra->next=p;
ra=p;
}
else{
rb->next=p;
rb=p;
}
p=p->next;
}
ra->next=NULL;
rb->next=NULL;
return B;
}
11 设C={a1,b2,a2,b2,···,an,bn} ,采用带头结点的方式,将其拆分为A{a1,a2,···,an} ,B{bn,···,b2,b1}
**思想:**和10题类似,A表后插保证和原表顺序一致,B表前插实现逆序
LinkList divide_List2(LinkList &A){
LNode *B;
B=(LinkList)malloc(sizeof(LNode *));
B->next=NULL;
LNode *p=A->next,*q;
LNode *ra=A;
A->next=NULL;
while(p!=NULL){
ra->next=p;
ra=p;
p=p->next;
if(p!=NULL){
q=p->next;
p->next=B->next;
B->next=p;
p=q;
}
}
ra->next=NULL;
return B;
}
12 在一个有序单链表中,有数值相同的元素,设计算法删除相同的元素,使表中不再含有相同的元素。L={2,5,5,5,9,9,15,18,18,36} –>L{2,5,9,15,18,36}
void delete_same(LinkList &L){
LNode *p=L->next,*q;
if(p==NULL){
return;
}
while(p->next!=NULL){
q=p->next;
if(p->data==q->data){
p->next=q->next;
free(q);
}
else{
p=q;
}
}
}
13 有两个按递增次序排列的单链表,设计算法使得将这两个链表合并成按元素递减次序排列的单链表,要求利用原来的链表结点存放合并后的单链表
void merge_Des(LinkList &A,LinkList &B){
LNode *r;
LNode *pa=A->next,*pb=B->next;
A->next=NULL;
while(pa&&pb){
if(pa->data < pb->data){
r=pa->next;
pa->next=A->next;
A->next=pa;
pa=r;
}
else{
r=pb->next;
pb->next=A->next;
A->next=pb;
pb=r;
}
}
if(pa){
pb=pa;
}
while(pb){
r=pb->next;
pb->next=A->next;
A->next=pb;
pb=r;
}
free(B);
}
14 设A和B是两个带头结点的单链表,其中元素递增有序,设计一个算法从A和B中公共元素中产生新链表C
*思想:寻找两个链表公共结点,参照8题;(公共结点和公共元素不同)***此题寻找公共元素,这个题两个链表都是递增有序的,所以可以从表头依次比较,元素值不相等,小的元素指针后移再比较;元素值相等,创建一个新的结点,后插法保持有序
A={4,9,9,15,26,34,58,59,66} ,B={15,26,59,66,69,72} ,C={15,26,59,66}
LinkList get_Common(LinkList &A,LinkList &B){
LinkList C=(LinkList)malloc(sizeof(LNode *));
C->next=NULL;
LNode *rc=C;
LNode *pa=A->next,*pb=B->next;
while(pa&&pb){
if(pa->data < pb->data){
pa=pa->next;
}
else if(pa->data > pb->data){
pb=pb->next;
}
else{
LNode *s=(LNode *)malloc(sizeof(LNode *));
s->data=pa->data;
rc->next=s;
rc=s;
pa=pa->next;
pb=pb->next;
}
}
rc->next=NULL;
return C;
}
15 已知两个链表A和B分别表示两个集合,其元素递增有序,设计一个算法求A,B的交集,并存放在A中。(和上题类似,记得动手实现)
16 两个整数序列,A={a1,a2,···,an} ,B={b1,b2,···,bn} ,判断B是否是A的连续子序列
**思想:**其实是字符串模式匹配的链式表示,试着优化
int pattern(LinkList A,LinkList B){
LNode *pa=A->next;
LNode *pb=B->next;
LNode *pre=A->next;
if(pa==NULL || pb==NULL){
return 0;
}
while(pa&&pb){
if(pa->data == pb->data){
pa=pa->next;
pb=pb->next;
}
else{
pre=pre->next;
pa=pre;
pb=B->next;
}
}
if(pb==NULL){
return 1;
}
else{
return 0;
}
}
循环双链表的基本操作
typedef struct DNode{
int data;
struct DNode *prior,*next;
}DNode,*DLinkList;
void buildDLink(DLinkList &L){
L=(DLinkList)malloc(sizeof(DNode *));
L->next=L;
L->prior=L;
DNode *s;
int x;
cout<<"输入一个整数:";
cin>>x;
while(x!=9999){
s=(DNode *)malloc(sizeof(DNode *));
s->data=x;
s->next=L->next;
L->next->prior=s;
L->next=s;
s->prior=L;
cout<<"输入一个整数:";
cin>>x;
}
}
void printDLink(DLinkList L){
DNode *p;
p=L->next;
while(p!=L){
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
17 判断带头结点循环双链表是否对称
**思想:**p从左到右,r从右到左,直到它们指向同一个结点(奇数个结点)或相邻结点(偶数个结点)为止。注意偶数结点的判断条件
int judge_Symmetry(DLinkList L){
DNode *p=L->next,*r=L->prior;
while(p!=r && r->next!=p){
if(p->data==r->data){
p=p->next;
r=r->prior;
}
else{
return 0;
}
}
return 1;
}
循环单链表的基本操作
void ListHeadInsert0(LinkList &L){
LNode *s;
int x;
L=(LinkList)malloc(sizeof(LNode *));
L->next=L;
cout<<"输入一个整数:";
cin>>x;
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode *));
s->data=x;
s->next=L->next;
L->next=s;
cout<<"输入一个整数:";
cin>>x;
}
}
void printLinkList0(LinkList L){
LNode *p;
p=L->next;
while(p!=L)
{
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
18 有两个循环单链表,链表头指针分别为A,B,编写函数将B连接到A之后,要求链接之后的链表仍保持循环链表形式
LinkList Link(LinkList &A,LinkList B){
LNode *p=A->next,*q=B->next;
while(p->next!=A){
p=p->next;
}
while(q->next!=B){
q=q->next;
}
p->next=B->next;
B->next=NULL;
q->next=A;
return A;
}
19 设有一个带头结点的循环单链表,结点均为正整数,设计一个算法,反复找出表中最小值结点并输出,然后将该结点删除,直到单链表空为止,最后释放头结点
void printDelete_Min(LinkList &L){
LNode *pre,*p;
LNode *minpre,*minp;
while(L->next!=L){
pre=L;
p=L->next;
minpre=pre;
minp=p;
while(p!=L){
if(p->data < minp->data){
minp=p;
minpre=pre;
}
pre=p;
p=p->next;
}
cout<<minp->data<<" ";
minpre->next=minp->next;
free(minp);
}
free(L);
}
21 已知一个带头结点的单链表,在不改变链表结构的前提下,设计一个算法查找链表中倒数第k个位置上的元素;查找成功,输出结点的值,返回1;查找失败,返回0。
**思想:**两个指针变量p,q,初始时指向L->next,首先p指针移动到第k个元素时,q指针开始和p指针同步移动,当p移动到最后一个结点时,q当前所指就是倒数第k个结点。
int search_K(LinkList L,int k){
LNode *p=L->next,*q=L->next;
int count=0;
while(p!=NULL){
if(count<k){
count++;
}
else{
q=q->next;
}
p=p->next;
}
if(count<k){
cout<<"k越界"<<endl;
return 0;
}
cout<<"倒数第"<<k<<"个位置的元素值:"<<q->data<<endl;
return 1;
}
22 寻找链表公共结点
23 用单链表保存m个整数,结点值|data|<=n(n为正整数)。要求设计一个时间复杂度尽可能高效的算法,对于链表中data的绝对值相等的结点,仅保留第一次出现的结点而删除其余绝对值相等的结点,例如L={21,-15,-15,-1,15} ,经过算法之后,L={21,-15,-7}
void delete_Abs_Same(LinkList &L,int n){
LNode *p=L,*r;
int tag[n+2]={0};
int m;
while(p->next!=NULL){
m=abs(p->next->data);
if(tag[m]==0){
tag[m]=1;
p=p->next;
}
else{
r=p->next;
p->next=r->next;
free(r);
}
}
}
24 设计算法判断一个链表是否有环,如果有,返回环的入口结点
2(a+x)=a+n*r+x ,即 a=n*r-x
LNode * FindLoopStart(LinkList L){
LNode *fast=L->next,*slow=L->next;
while(slow!=NULL && fast->next!=NULL){
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
break;
}
}
if(slow==NULL || fast->next==NULL){
return NULL;
}
LNode *head=L->next,*meet=slow;
while(head!=meet){
head=head->next;
meet=meet->next;
}
return head;
}
int main(){
LinkList L;
ListHeadInsert(L);
printLinkList(L);
LNode *p=L->next;
int dist=4;
while(dist--){
p=p->next;
}
cout<<"p->data="<<p->data<<endl;
LNode *r=L;
while(r->next!=NULL){
r=r->next;
}
r->next=p;
LNode *s = FindLoopStart(L);
cout<<"环的入口"<<s->data<<endl;
return 0;
}
25 设线性表L={a1,a2,a3,···,an-2,an-1,an} ,采用带头结点的单链表保存,设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列各元素,使L={a1,an,a2,an-1,a3,an-2,···}
**思想:**不能借助辅助空间(栈),为了方便取后半段的元素,将后半段元素原地逆置(前插法),否则每次取元素都要遍历一次链表
void change_List(LinkList &L){
LNode *p,*r,*s,*t;
p=L,r=L;
while(r->next!=NULL){
p=p->next;
r=r->next;
if(r->next!=NULL){
r=r->next;
}
}
r=p->next;
p->next=NULL;
while(r!=NULL){
t=r->next;
r->next=p->next;
p->next=r;
r=t;
}
r=p->next;
p->next=NULL;
s=L->next;
while(r!=NULL){
t=r->next;
r->next=s->next;
s->next=r;
s=r->next;
r=t;
}
}
第三章栈和队列
栈和队列基础操作
#define MaxSize 50
typedef struct{
int data[MaxSize];
int top;
}SqStack;
typedef struct{
int data[MaxSize];
int front,rear;
}SqQueue;
InitStack(SqStack &S){
S.top=-1;
}
InitQueue(SqQueue &Q){
Q.front=Q.rear=0;
}
bool StackEmpty(SqStack S){
if(S.top==-1){
return true;
}else{
return false;
}
}
bool QueueEmpty(SqQueue Q){
if(Q.front==Q.rear){
return true;
}else{
return false;
}
}
bool push(SqStack &S,int x){
if(S.top==MaxSize-1){
cout<<"栈满";
return false;
}
S.data[++S.top]=x;
return true;
}
bool pop(SqStack &S,int &x){
if(S.top==-1){
cout<<"栈空";
return false;
}
x=S.data[S.top--];
return true;
}
bool GetTop(SqStack S,int &x){
if(S.top==-1){
cout<<"栈空";
return false;
}
x=S.data[S.top];
return true;
}
bool EnQueue(SqQueue &Q,int x){
if((Q.rear+1)%MaxSize==0){
cout<<"队满"<<endl;
return false;
}
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%MaxSize;
return true;
}
bool DeQueue(SqQueue &Q,int &x){
if(Q.front==Q.rear){
cout<<"队空"<<endl;
return false;
}
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
return true;
}
链式队列基本操作
typedef struct LinkNode{
int data;
struct LinkNode *next;
}LinkNode;
typedef struct{
LinkNode *front,*rear;
}LinkQueue;
void InitLinkQueue(LinkQueue &Q){
Q.front=Q.rear=(LinkNode *)malloc(sizeof(LinkNode *));
Q.rear->next=NULL;
}
bool LinkQueueEmpty(LinkQueue Q){
if(Q.front==Q.rear){
return true;
}else{
return false;
}
}
void EnLinkQueue(LinkQueue &Q,int x){
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode *));
s->data=x;
s->next=NULL;
Q.rear->next=s;
Q.rear=s;
}
bool DeLinkQueue(LinkQueue &Q,int &x){
if(Q.rear==Q.front){
return false;
}
LinkNode *q=Q.front->next;
x=q->data;
Q.front->next=q->next;
if(Q.rear==q){
Q.rear=Q.front;
}
free(q);
return true;
}
第一节
4 设单链表头指针为L,data为字符型,设计算法判断该链表的全部n个元素是否对称
int judge_Symmetry(LinkList L,int n){
LNode *p;
char s[n/2];
p=L->next;
int i;
for(i=0;i<n/2;i++){
s[i]=p->data;
p=p->next;
}
i--;
if(n%2==1){
p=p->next;
}
while(p!=NULL && p->data==s[i]){
i--;
p=p->next;
}
if(i==-1){
return 1;
}
else{
return 0;
}
}
5 设计共享栈的出栈,入栈操作
typedef struct{
int data[MaxSize];
int top[2];
}SqStack;
void InitStack(SqStack &S){
S.top[0]=-1;
S.top[1]=MaxSize;
}
bool push(SqStack &S,int x,int i){
if(i<0 || i>1){
return false;
}
if(S.top[1]-S.top[0]==1){
cout<<"栈满";
return false;
}
switch(i){
case 0:
{
S.data[++S.top[0]]=x;
return true;
break;
}
case 1:
{
S.data[--S.top[1]]=x;
return true;
break;
}
}
}
int pop(SqStack &S,int i){
if(i<0 || i>1){
return -1;
}
switch(i){
case 0:
{
if(S.top[0]==-1){
cout<<"栈空";
return -1;
}
else{
return S.data[S.top[0]--];
}
break;
}
case 1:
{
if(S.top[1]==MaxSize){
cout<<"栈空";
return -1;
}
else{
return S.data[S.top[1]++];
}
break;
}
}
}
第二节
1 希望循环队列都能得到利用,则需设置一个标志域tag,实现入队出队的算法
#define MaxSize 50
typedef struct{
int data[MaxSize];
int front,rear;
int tag;
}SqQueue;
void InitQueue(SqQueue &Q){
Q.front=Q.rear=0;
Q.tag=0;
}
bool EnQueue(SqQueue &Q,int x){
if(Q.rear==Q.front && Q.tag==1){
cout<<"栈满";
return false;
}
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%MaxSize;
Q.tag=1;
return true;
}
bool DeQueue(SqQueue &Q,int &x){
if(Q.rear==Q.front && Q.tag==0){
cout<<"栈空";
return false;
}
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
Q.tag=0;
return true;
}
2 利用栈和队列实现对队列的逆置
void Reverse_Queue(SqQueue &Q,SqStack &S){
int x;
while(!QueueEmpty(Q)){
DeQueue(Q,x);
push(S,x);
}
while(!StackEmpty(S)){
pop(S,x);
EnQueue(Q,x);
}
}
3 利用两个栈模拟一个队列,已知栈有下面4个基础操作
**思想:**对S2的出栈操作用作出队,若S2为空,则先将S1中的所有元素送入S2;
对S1的入栈操作用作入队,若S1满,必须先保证S2为空,才能将S1中的元素全部插入S2中
int QnQueue2(Stack &S1,Stack &S2,int e){
if(!StackOverflow(S1)){
Push(S1,e);
return 1;
}
if(StackOverflow(S1) && StackEmpty(S2)){
cout<<"队列满"<<endl;
return 0;
}
if(StackOverflow(S1) && StackEmpty(S2)){
while(!StackEmpty(S1)){
Pop(S1,x);
Push(S2,x);
}
}
Push(S1,e);
return 1;
}
void DeQueue2(Stack &S1,Stack &S2,int &x){
if(!StackEmpty(S2)){
Pop(S2,x);
}
else if(StackEmpty(S1)){
cout<<"队列空"<<endl;
}
else{
while(!StackEmpty(S1)){
Pop(S1,x);
Push(S2,x);
}
Pop(S2,x);
}
}
int QueueEmpty2(Stack S1,Stack S2){
if(StackEmpty(S1)&&StackEmpty(S2)){
return 1;
}
else{
return 0;
}
}
第三节
1 写一个算法实现括号匹配
bool BracketCheck(char *str){
SqStack S;
InitStack(S);
int i=0;
int e;
while(str[i]!='\0'){
switch(str[i]){
case '{':
Push(S,'{');
break;
case '[':
Push(S,'[');
break;
case '(':
Push(S,'(');
break;
case '}':
Pop(S,e);
if(e!='{'){
printf("匹配失败!");
return false;
}
break;
case ']':
Pop(S,e);
if(e!='['){
printf("匹配失败!");
return false;
}
break;
case ')':
Pop(S,e);
if(e!='('){
printf("匹配失败!");
return false;
}
break;
default:
break;
}
i++;
}
if(!StackEmpty(S)){
printf("匹配失败!");
return false;
}
else{
printf("匹配成功!");
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(str[i]==')' && topElem!='(')
return false;
if(str[i]==']' && topElem!='[')
return false;
if(str[i]=='}' && topElem!='{')
return false;
}
}
return StackEmpty(S);
}
3 利用栈实现如下递归调用
struct newstack{
int no;
double value;
};
double P(int n,double x){
newstack st[MaxSize];
int top=-1;
int i;
double fv1=1,fv2=2*x;
for(i=n;i>=2;i--){
top++;
st[top].no=i;
}
while(top>=0){
st[top].value=2*x*fv2-2*(st[top].no-1)*fv1;
fv1=fv2;
fv2=st[top].value;
top--;
}
if(n==0){
return fv1;
}
return fv2;
}
4 某汽车轮渡口,过江渡船每次能载10辆车过江,过江车辆有客车和货车:同类车辆先到先上船;客车先与货车上船,且每上4辆客车,才能上一辆货车;若等待客车不足4辆,则以货车代替;若无货车等待,允许客车都上船。
void Manager(SqQueue &q1,SqQueue &q2,SqQueue &Q){
int i=0,j=0;
while(j<10){
int x;
if(i<4 && !QueueEmpty(q1)){
DeQueue(q1,x);
EnQueue(Q,x);
i++;
j++;
}
else if(i==4 && !QueueEmpty(q2)){
DeQueue(q2,x);
EnQueue(Q,x);
j++;
i=0;
}
else{
while(j<10 && i<4 && !QueueEmpty(q2)){
DeQueue(q2,x);
EnQueue(Q,x);
j++;
i++;
}
i=0;
}
if(QueueEmpty(q1) && QueueEmpty(q2)){
j=11;
}
}
}
第四章串
-
顺序存储 #define MAXLEN 255
typedef struct{
char ch[MAXLEN];
int length;
}SString
这种方式直接分配一个固定长度的存储区,销毁时系统会自动回收 -
堆分配存储(动态分配) 仍然是一组地址连续的存储单元存放串值,但是存储空间是动态分配得到的 typedef struct{
char *ch;
int length;
}HString
S.ch=(char *)malloc(MAXLEN*sizeof(char));
在堆中的存储,用malloc() 申请的空间,需要手动free() 释放 -
块链存储 用链表方式存储字符串值 一个结点存放一个字符时存储密度低,可以存放多个字符
StrAssign(&T,chars) :赋值操作,把串T 赋值为`chars``- ``StrCompare(S,T)
: S>T,则返回值 >0; S=T,则返回值 =0;若 S<T,则返回值 <0` StrLength(S) :求串长SubString(&Sub,S,pos,len) :求子串,用Sub 返回串S 的第pos 个字符起长度为len 的子串Index(S,T) :定位操作,返回子串T 在主串S 中首次出现的位置ClearString(&S) :S 串清空DestroyString(&S) :销毁,归还空间
int Index(SString S,SString T){
int i=1;
int n=StrLength(S);
int m=StrLength(T);
SString sub;
while(i<=n-m+1){
SubString(sub,S,i,m);
if(StrCompare(T,sub)!=0){
i++;
}
else{
return i;
}
}
return 0;
}
int Index2(SString S,SString T){
int k=1;
int i=k,j=1;
while(i<=S.length && j<=T.length){
if(S.ch[i-1]==T.ch[j-1]){
i++;
j++;
}
else{
k++;
i=k;
j=1;
}
}
if(j>T.length){
return k;
}
else{
return 0;
}
}
第五章树和二叉树
5 已知一颗二叉树按顺序存储结构进行存储,求编号分别为 i 和 j 的两个结点的最近的公共祖先结点
**思想:**二叉树中两个任意结点必然存在最近的祖先结点,顺序存储结构中,任一结点 i 的双亲结点的编号为 i/2,一直往上层寻找,直到 i/2 等于 j/2 或者 j
char Comm_Ancestor(char T[],int i,int j){
if(T[i]!='#' && T[j]!='#'){
while(i!=j){
if(i>j){
i=i/2;
}
else{
j=j/2;
}
}
return T[i];
}
}
递归遍历实现
typedef struct BiTNode{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree createBiTree(){
BiTNode *r;
char s;
cin>>s;
if(s=='#'){
r=NULL;
}
else{
r=(BiTNode *)malloc(sizeof(BiTNode *));
r->data=s;
cout<<"输入 "<<s<<" 的左孩子结点('#'表示为空):";
r->lchild=createBiTree();
cout<<"输入 "<<s<<" 的右孩子结点('#'表示为空):";
r->rchild=createBiTree();
}
return r;
}
void visit(BiTNode *T){
if(T!=NULL){
cout<<T->data<<endl;
}
}
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){
SqStack S;
InitStack(S);
BiTNode *p=T;
while(!StackEmpty(S) || p){
if(p){
Push(S,p);
p=p->lchild;
}
else{
Pop(S,p);
visit(p);
p=p->rchild;
}
}
}
**先序思想:**和中序类似,只是访问的时机在入栈之前
void PreOrder2(BiTree T){
SqStack S;
InitStack(S);
BiTNode *p=T;
while(!StackEmpty(S) || p){
if(p){
visit(p);
Push(S,p);
p=p->lchild;
}
else{
Pop(S,p);
p=p->rchild;
}
}
}
层次遍历
**思想:**将根结点入队,出队并访问,如果其存在左孩子,则将其入队,若存在右孩子,同样入队;然后队列不空时进行出队访问,左右孩子入队出队。
void leverOrder(BiTree T){
BQueue Q;
InitBQueue(Q);
BiTree p;
EnBQueue(Q,T);
while(!emptyBQueue(Q)){
DeBQueue(Q,p);
visit(p);
if(p->lchild!=NULL){
EnBQueue(Q,p->lchild);
}
if(p->rchild!=NULL){
EnBQueue(Q,p->rchild);
}
}
}
中序线索化
typedef struct ThreadNode{
char data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag;
}ThreadNode,*ThreadTree;
void InThread(ThreadNode *p,ThreadNode *pre){
if(p!=NULL){
InThread(p->lchild,pre);
if(p->lchild==NULL){
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL && pre->rchild==NULL){
pre->rchild=p;
pre->rtag=1;
}
pre=p;
InThread(p->rchild,pre);
}
}
void CreateInThread(ThreadTree T){
ThreadNode *pre=NULL;
if(T!=NULL){
InThread(T,pre);
pre->lchild=NULL;
pre->rtag=1;
}
}
ThreadNode *firstNode(ThreadNode *p){
while(p->ltag==0){
p=p->lchild;
}
return p;
}
ThreadNode *nextNode(ThreadNode *p){
if(p->rtag==0){
return firstNode(p->rchild);
}
else{
return p->rchild;
}
}
void InOrder3(ThreadTree T){
for(ThreadNode *p=firstNode(T) ; p!=NULL ; p=nextNode(p)){
visit(p);
}
}
中序线索化另外的方式
typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag;
}ThreadNode,* ThreadTree;
ThreadNode *pre=NULL;
CreateInOrder(ThreadTree T){
pre=NULL;
if(T!=NULL){
InThread(T);
if(pre->rchild==NULL){
pre->rtag=1;
}
}
}
InThread(ThreadTree T){
if(T!=NULL){
InThread(T->lchild);
Visit(T);
InThread(T->rchild);
}
}
Visit(ThreadNode *q){
if(q->lchild==NULL){
q->lchild=pre;
q-ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL){
pre->rchild=q;
pre-rtag=1;
}
pre=q;
}
5.3 非递归实现后序遍历
#define MaxSize 50
typedef struct BiTNode{
char data;
struct BiTNode *lchild,*rchild;
int tag;
}BiTNode,*BiTree;
BiTree createBiTree(){
BiTNode *r;
char s;
cin>>s;
if(s=='#'){
r=NULL;
}
else{
r=(BiTNode *)malloc(sizeof(BiTNode));
r->data=s;
r->tag=0;
cout<<"输入 "<<s<<" 的左孩子结点('#'表示为空):";
r->lchild=createBiTree();
cout<<"输入 "<<s<<" 的右孩子结点('#'表示为空):";
r->rchild=createBiTree();
}
return r;
}
void PostOrder2(BiTree T){
struct BiTNode *stack[MaxSize];
int top=-1;
BiTNode *p=T;
while(p || top!=-1){
if(p){
top++;
stack[top]=p;
p=p->lchild;
}
else{
p=stack[top];
if(p->rchild!=NULL && p->rchild->tag==0){
p=p->rchild;
}
else{
p=stack[top];
top--;
p->tag=1;
cout<<p->data<<endl;
p=NULL;
}
}
}
}
第六章
陆续更新···
|