線性表
設計一個時間複雜度為O(N)的演算法,實現將數組A[n]中所有元素迴圈左移k個位置
分析:把數組ab轉換成數組ba,先把a置逆,再把b置逆,最後將a,b置逆。
Void converse(char a[],int n,int k)
{
Reverse(a,0,k-1);
Reverse(a,k,n-1);
Reverse(a,0,n-1);
}
Void reverse(char A[],int from,int to)
{
For(i=0;i<(to-from+1)/2;i++)
{
A[from+i]<->A[to-i]
}
}
設計演算法實現單鏈表就地置逆
分析:即將每個結點的指標由指向該結點的後繼改為指向該結點的前驅。在掃描過程中設定三個指標。
Void reverse(node *first)
{
P=first->next; pre=NULL; //如果針對迴圈鏈表,則只需要把NULL改為頭指標first即可
While(p!=NULL)
{
R=p->next;
p->next=pre;
pre=p;
p=r;
}
First->next=pre;
}
棧和隊列
設計遞迴演算法求解在n元集合A={1,2…n}中選取k個元素的所有組合。
分析:第一次選擇有包括1與不包括1兩種情況,包括1在後續中選k-1個,不包括1在後續中選k個。
Void comb(int I,int n,int k)
{
If(n-i+1<=k)
{
For(i=1;i<=k;i++)
Printf(B[i]);
Printf(“/n”);
}
Else
{
B[i]=A[i];
Comb(i+1,n,k-1);
Comb(i+1,n,k);
}
}
樹與二叉樹
已知深度為h的二叉樹採用順序儲存結構已存放於數組B[1….2^h-1]中,編寫遞迴演算法產生該二叉樹的二叉鏈表結構。
分析:可以採用一個隊列,先將二叉樹的根結點即數組的第一個元素建立對應的二叉鏈表的根結點,併入隊列,然後對隊列中的元素依次進行出隊並考查該結點。
Void seqtobi(binode *T, elemtype BT[], int n)
{
Len=2^h-1;
T=(binode *)malloc(sizeof(binode));
T->data=BT[1];
Front=0;rear=0;
Tq.ptr=T; tq.num=1;Q[++rear]=tq;
While(front!=rear)
{
Tq=Q[++front];p=tq.ptr;i=tq.num;
If(BT[2*i]==0||2*i>len) p->lchild=NULL; //左子樹為空白時
Else
{
p->lchild=(binode*)malloc(sizeof(binode));
p->lchild->data=BT[2*i];
tq.ptr=p->lchild;tq.num=2*i;Q[++rear]=tq; //左孩子及其編號入隊
}
If(BT[2*i+1]==0||2*i+1>len) p->lchild=NULL; //右子樹為空白時
Else
{
p->rchild=(binode*)malloc(sizeof(binode));
p->rchild->data=BT[2*i+1];
tq.ptr=p->rchild;tq.num=2*i+1;Q[++rear]=tq; //右孩子及其編號入隊
}
}
}
一棵二叉樹以二叉鏈表格儲存體,求二叉樹第k層上葉子結點的個數
分析:設定last記載當前訪問結點所在的層次,將last指向該層地最右結點,當last結點處理完則遍曆進入下一層。
Int leaflevel(binode *T,int k)
{
If(T==NULL) return 0 ;
Leaf=0 ;
Front=0 ;rear=0 ;
Last=1 ;level=1 ;//last是二叉樹同層最右結點的指標
Q[++rear]=T ;
While(front<rear)
{
P=Q[++rear] ;
If(level==k&& !p->lchild&& !p->rchild) leaf++; //統計葉子結點個數
If(p->lchild)Q[++rear]=p->lchild; //左孩子入隊
If(p->rchild)Q[++rear]=p->rchild;//右孩子入隊
If(front==last) //正在處理的結點是該層最右結點
{
Level++;
Last=rear;
}
If(level>k) return leaf; //層數大於k無需繼續處理
}
}
中序線索鏈表的構造
Void inthrbitree(thrnode *root)
{
If(root==NULL) return;
Inthrbitree(root->lchild);
If(!root->lchild) //對root左指標進行處理
{
Root->ltag=1;
Root->lchild=pre;
}
If(!root->rchild) root->rtag=1;//對root的右指標進行處理
If(pre->rtag==1) pre->rchild=root;//設定pre的後繼線索
Pre=root;
Inthrbitree(root->rchild);
}
求最近公用祖先,p,q分別為指向該二叉樹中任意兩個結點的指標,找到p,q最近公用祖先r
Binode *ancestor(binode *root,binode *p,binode *q,binode *r)
{
Top=0;bt=root;
While(bt!=NULL||top>0)
{
While(bt!=NULL)//沿左分支向下
{
Top++;s[top].ptr=bt;s[top].flag=1;
Bt=bt->lchild;
}
While(top!=0&&s[top].flag==2)
{
If(s[top].ptr==p)
{
For(i=1;i<=top;i++) //將棧s的結點拷貝到棧t中
T[i]=s[i];
Top1=top;
}
If(s[top].ptr==q) //訪問到結點q
{
For(i=top;i>0;i–)
{
For(j=top1;j>0;j–)
{
If(t[j].ptr==s[i].ptr)//找到最近的公用祖先
Return s[i].ptr;
}
}
}
Top–;
}
If(top!=0) //準備沿右分支遍曆
{
S[top].flag=2;bt=s[top].ptr->rchild;
}
}
Return NULL;
}
圖
深度優先遍曆演算法
Void dfs(mgraph G,int v)
{
Printf(G.vertex[v]);visited[v]=1;
For(j=0;j<G.vertexNum;j++)
If(G.arc[v][j]==1&&visited[j]==0) dfs(G,j);
}
廣度優先遍曆演算法
Void bfs(mgraph G,int v)
{
Front=rear=-1;
Printf(G.vertex[v]); visited[v]=1;Q[++rear]=v; //被訪問頂點入隊
While(front!=rear)
{
V=Q[++front];
For(j=0;j<G.vertexNum;j++)
{
If(G.arc[v][j]==1&&visited[j]==0)
{
Printf(G.vertex[j]);visited[j]=1;Q[++rear]=j;
}
}
}
}
Prim演算法
Void prim(mgraph G)
{
For(i=1;i<G.vertexNum;i++)
{
Lowcost[i]=G.arc[0][i];
Adjvex[i]=0;
}
Lowcost[0]=0;
For(i=1;i<G.vertexNum;i++)
{
K=minedge(lowcost,G.vertexNum); //在lowcost中尋找最短邊的頂點x
Printf(k,adjvex[k],lowcost[k]); //輸出加入到TE中的邊
Lowcost[k]=0; //將頂點K加入集合U中
For(j=1;j<G.vertexNum;j++)
{
If(G.arc[k][j]<lowcost[j])
{
Lowcost[j]=G.arc[k][j];
Adjvex[j]=k;
}
}
}
}
Dijkstra演算法
Dist[i]:表示當前找到的從源點v到終點vi的最短路徑長度
Path[i]:表示當前找到的從源點v到終點vi的最短路徑
S[n]:存放源點和已經產生的終點,初態為只有一個源點v
Void dijkstra(Mgraph G,int v)
{
For(i=0;i<G..vertexNum;i++) //初始化dist[n],path[n]
{
Dist[i]=G.arc[v][i];
If(dist[i]!=∞) path[i]=G.vertex[v]+G.vertex[i];
Else path[i]=””;
}
S[0]=G.vertex[v]; //初始化集合s
Dist[v]=0; //標記頂點v的源點
Num=1;
While(num<G.vertexNum)
{
For(k=0,i=1;i<G.vertexNum;i++)
{
If((dist[i]<dist[k])&&dist[i]!=0) k=I;
}
Printf(dist[k],path[k]);
S[num++]=G.vertex[k]; //將新產生的終點vk加入集合S
Dist[k]=0; //置頂點vk為已產生終點標記
For(i=0;i<G.vertexNum;i++)
If(dist[i]>dist[k]+G.arc[k][i])
{
Dist[i]=dist[k]+G.arc[k][i];
Path[i]=path[k]+G.vertex[i];
}
}
}
尋找
二叉排序樹的刪除演算法
Void deletebst(binode *p,binode *f)
{
If(!p->lchild&&!p->rchild) //p為葉子結點
{
f->lchild=NULL;delete p;
}
Else if(!p->rchild) //p只有左子樹
{
f->lchild=p->lchild;delete p;
}
Else if(!p->lchild) //p只有右子樹
{
f->lchild=p->rchild;delete p;
}
Else //p左右子樹均不為空白
{
Par=p; s=p->rchild;
While(s->lchild!=NULL)
{
Par=s;s=s->lchild;
}
p->data=s->data;
if(par==p)
par->rchild=s->rchild;
else
par->lchild=s->rchild;
delete s;
}
}
排序
快速排序的一次劃分
Int partition(int r[],int first,int end)
{
I=first;j=end;
While(i<j)
{
While(i<j&&r[i]<=r[j]) j–; //右側掃描
If(i<j)
{
R[i]<->r[j];i++;
}
While(i<j&&r[i]<=r[j]) i++;//左側掃描
If(i<j)
{
R[j]<->r[i]; j–;
}
}
Return I;
}
Void quicksort(int r[],int first,int end)
{
If(first<end)
{
Pivot=partition(r,first,end);//一次劃分,pivot為軸的最終位置
Quicksort(r,first,pivot-1); //對左側進行劃分
Quicksort(r,pivot+1,end);//對右側進行劃分
}
}
堆調整演算法,m為堆中最後一個結點的編號,k為當前要篩選結點的編號
Void shift(int r[],int k,int m)
{
I=k;j=2*I; //i為要篩選的結點,j為i的左孩子
While(j<m)
{
If(j<m&&r[j]<r[j+1]) j++; //比較i的左右孩子,j為較大者
If(r[i]>r[j]) break; //根結點大於較大者
Else
{
R[i]<->r[j]; //將根結點與結點j交換
I=j;j=2*I; //被篩選結點位於原來j結點位置
}
}
}