typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //如果xtag为0,则xchild指向实际的孩子;如果xtag为1,则xchild指向前驱or后继。
}
Thread *Lastnode(ThreadNode *p){
while( (p->ltag == 0 && p->lchild != NULL) || (p->rtag == 0 && p->rchild != NULL) ){
while(p->rtag == 0 && p->rchild != NULL) p = p->rchild;
if(p->ltag == 0 && p->lchild != NULL) p = p->lchild;
}
return p;
}
f->lchild
为根节点**的二叉树,进行先序遍历的最后一个结点,则是p的先序前驱
//三叉链表
typedef struct TriTNode
{
int data;
struct TriTNode *lchild, *rchild;
int ltag,rtag;
struct TriTnode *parent; //多出一个域指向父结点
}TriTNode,*TriTree;
//略
Thread *Nextnode(ThreadNode *p){
if(p->rtag == 0 && p->rchild != NULL){
if(p->ltag == 0 && p->lchild){ //左孩子存在
return p->lchild;
}
}
//(左孩子不存在) or (p->rtag == 1)
return p->rchild; //不论是有实际的右孩子,还是指向后继,只要没有实际的左孩子,都是直接返回p->rchild
}
ThreadNode *Firstnode(ThreadNode *p){
while(p->ltag==0) //左孩子存在,则一直往左下
p = p->lchild;
return p;
}
ThreadNode *Lastnode(ThreadNode *p){
while(p->rtag == 0){
p = p->rchild;
}
return p;
}
ThreadNode *Prenode(ThreadNode *p){
if(p->ltag == 0){ //lchild指向的是实际的左孩子
return Lastnode(p->lchild); //前驱是 左子树中最右下的结点,即以结点p左孩子为根节点,找 Lastnode(p->lchild)
}
return p->rchild;
}
1 ThreadNode *Nextnode(ThreadNode *p){
2 if(p->rtag == 0){ //rchild指向的是实际的右孩子
3 return Firstnode(p->rchild); //后继是 右子树中最左下的结点,即以结点p的右孩子为根节点,找 Firstnode(p->rchild)
4 }
5 return p->rchild;
6 }
Thread *Firstnode(ThreadNode *p){
while( (p->ltag == 0 && p->lchild != NULL) || (p->rtag == 0 && p->rchild != NULL) ){
while(p->ltag == 0 && p->lchild != NULL) p = p->lchild;
if(p->rtag == 0 && p->rchild != NULL) p = p->rchild;
}
return p;
}
Thread *Prenode(ThreadNode *p){
if(p->ltag == 0 && p->lchild != NULL){
if(p->rtag == 0 && p->rchild){ //右孩子存在
return p->rchild;
}
}
//(右孩子不存在) or (p->ltag == 1)
return p->lchild; //不论是有实际的左孩子,还是指向前驱,只要没有实际的右孩子,都是直接返回p->lchild
}
Firstnode(f->rchild)
typedef char VertexType;
typedef int EdgeType;
typedef struct{
VertexType Vex[MaxVertexNum];
EdgeType Edge[MaxVertexNum][MaxVertextNum];
int vexnum,arcnum;
}MGragh;
#define MaxVertexNum 100
typedef struct ArcNode{
int adjvex;
Struct ArcNode* next;
}ArcNode;
typedef struct VNode{
Vertex data;
ArcNode *first;
}VNode;
typedef struct{
VNode* vertices = new VNode[MaxVertexNum];
int vexnum,arcmun;
}ALGragh;
bool visited[MAX_VERTEX_NUM];
queue <int> Q;
bool BFSTraverse(Gragh G){
for(int i=0; i<G.vexmun; i++){
visited[i] = False;
}
//统计连通分量,加一个变量。
//int componentNum = 0;
for(int i = 0; i<G.vexnum; ++i){
if(!visited[i]) BFS(G,i);
//componentNum++;
}
//cout<<"连通分量数量:"<
}
//邻接矩阵
//邻接矩阵下的-BFS广度优先搜索-时间复杂度:O(V^2)
//邻接矩阵下的空间复杂度:O(|V|)
void BFS(Graph G, int v){
visited[v] = True;
Q.push(v);
while(!Q.empty()){
int temp = Q.front();
Q.pop();
for(int i = 0; i<G.vexnum; i++){
if(G.Edge[temp][i] && !visited[i]){
visited[i] = True; //访问v
Q.push(i);
}
}
}
}
//邻接表
//邻接表下的-BFS广度优先搜索-时间复杂度:O(|V|+|E|),
//时间复杂度解释————查找所有顶点的邻接顶点花费的时间为O(|E|),访问所有顶点花费的时间O(|V|),相加得结果。
//邻接表下的空间复杂度:O(|V|)
//代码实现所用邻接表接口:
//int FirstNeighbor(G,x){},求图中顶点x的第一个邻接顶点,如果存在则返回该顶点编号,如果该顶点本身不存在or该顶点不存在任何邻接顶点,则返回-1
//int NextNeighbor(G,x,y){},求图中顶点x的邻接顶点y之后的下一个邻接顶点,如果存在则返回该顶点编号
void BFS(Graph G, int v){
visited[v] = True;
Q.push(v);
while(!Q.empty()){
int temp = Q.front();
Q.pop();
for(int i = FirstNeighbor(G,temp); i>=0 ; i = NextNeighbor(G,temp,i)){
if(!visited[i]){
visited[i] = True; //访问v
Q.push(i);
}
}
}
}
bool visited[MAX_VERTEX_NUM];
stack <int> S;
bool DFSTraverse(Gragh G){
for(int i=0; i<G.vexmun; i++){
visited[i] = False;
}
//统计连通分量,加一个变量。
//int componentNum = 0;
for(int i = 0; i<G.vexnum; ++i){
if(!visited[i]) DFS(G,i);
//componentNum++;
}
//cout<<"连通分量数量:"<
}
//邻接表-递归法
//邻接表下的-DFS深度优先搜索-时间复杂度:O(|V|+|E|)
//邻接表下的空间复杂度:O(|V|)
void DFS(Graph G, int v){
visited[v] = True;
for(int i = FirstNeighbor(G,v); w>=0; i=NextNeighbor(G,v,w)){
if(!visited[i]) DFS(G,i);
}
}
//邻接表-迭代法
void DFS(Graph G, int v){
visited[v] = True;
S.push(v);
while(!S.empty()){
int temp = S.top();
for(int i = FirstNeighbor(G,temp); i>=0; ){
if(!visited[i]){
S.push(i);
visited[i] = True;
temp = i;
i = FirstNeighbor(G,i);
}
else i = NextNeighbor(G,temp,i);
}
S.pop();
}
}
void DFS(Gragh G, int v){}
就能访问到n个顶点和n-1条边,则可以断定此图G为一棵树。bool visited[MAX_VERTEX_NUM];
bool isTree(Gragh& G){
//初始化visited数组,全部赋值False
for(int i = 1; i<=G.vexnum; i++) visited[i] = False;
//记录遍历中的边数和顶点数,而建立的变量
int Vnum = 0,Enum = 0;
DFS(G,1,Vnum,Enum); //把以上两个变量传入
if(Vnum==G.vexnum &&& Enum==G.vexnum-1) return True;
return False
}
void DFS(Graph G, int v; int &Vnum; int &Enum){
visited[v] = True;
Vnum++; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
int temp = FirstNeighbor(G,v);
while(temp>=0){
Enum++; //边数在找到一个连接的邻接顶点后,加加!!!!!!!!!!
if(!visited[w]) DFS(G,temp,Vnum,Enum);
temp = NextNeighbor(G,v,temp);
}
}
DFS(G,v)
或者BFS(G,v)
,执行结束后判断return visited[w]
,如果True,则存在,如果False,则不存在。void ShortestPath_DIJ(AMGraph G, int v0){
//用Dijkstra算法求有向网G的v0顶点到其余顶点的最短路径(邻接矩阵)
/*初始化
D[],记录其他顶点到V0的距离,每一轮都会更新,并选出一个最小的Vi,令S[i]=true;
S[],
Path[],记录最短路径中顶点i的前驱顶点
三个辅助数组*/
n=G.vexnum; //n为G中顶点的个数
for(v = 0; v<n; ++v){ //n个顶点依次初始化
S[v] = false; //S初始为空集
D[v] = G.arcs[v0][v]; //将v0到各个终点的最短路径长度初始化
if(D[v]< MaxInt) Path [v]=v0; //v0和v之间有弧,将v的前驱置为v0
else Path [v]=-1; //如果v0和v之间无弧,则将v的前驱置为-1
}//for-end
S[v0]=true; //将v0加入S
D[v0]=0; //源点到源点的距离为0
/*―开始主循环,每次求得v0到某个顶点v的最短路径,将v加到S集―*/
for(i=1;i<n; ++i){ //对其余n−1个顶点,依次进行计算
min= MaxInt;
for(w=0;w<n; ++w)
if(!S[w]&&D[w]<min){ //选择一条当前的最短路径,终点为v
v=w;
min=D[w];
}
S[v]=true; //将v加入S,即修改S[v]
for(w=0;w<n; ++w) //更新从v0出发到集合V−S上所有顶点的最短路径长度
if(!S[w] && (D[v]+G.arcs[v][w] < D[w]) ){
D[w]=D[v]+G.arcs[v][w]; //更新D[w]
Path[w]b=v; //更改w的前驱为v
}//if-end
}//for-end
}//ShortestPath_DIJ-end
Path[i][j]
和最短路径长度A[i][j]
/*初始化
A[][],A(k)[i][j]表示顶点i到顶点j的经过不大于k的顶点的最短路径长度
Path[][],Path(n)[i][j]表示顶点i到顶点j的最短路径中j的前驱顶点;
cost[][]即邻接矩阵
*/
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
A[i][j]=cost[i][j];
if(cost[i][j]< MAX ) Path[i][j]=i;
else Path[i][j]=0;
}//for-end
/*k轮双层for循环,不断更新A(k)[][]和Path(k)[][]*/
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if( A[i][j]> A[i][k]+ A[k][j] ){
A[i][j]= A[i][k]+ A[k][j];
Path[i][j]= Path[k][j] ;
}
void pathPrint(int m, int n, int Path[][]){
stack <int> pathStack;
pathStack.push(n);
for(int j = n; Path[m][j] != m; j = Path[m][j]) pathStack.push(Path[m][j]);
//打印最短路径
print(m);
while(!pathStack.empty()) print(pathStack.pop());
}
stack <int> S; //栈,用于存储入度为0的顶点
int indegree[G.vexnum]; //记录每个顶点的入度
int count = 0; //计数,记录当前已经输出的顶点数
while(!S.empty()){
}
//循环结束后,如果count等于G.vexnum,则该图是拓扑排序(该图没有环)
//如果count < G.vexnum,则该图不是拓扑排序(该图存在环)
经常对查找表做的操作有:
静态查找:对查找表的操作仅涉及以上的①和②,适合静态查找的有顺序查找、折半查找、散列查找
动态查找:需要对查找表进行动态的插入与删除操作,适合动态查找的有二叉排序树查找(改进:二叉平衡树、B树)、散列查找
关键字:能唯一标识一个数据元素的数据项的值
平均查找长度(ASL):求和(查找某个元素的概率*查找某个元素需要的比较次数),一般认为每一个数据元素的查找概率相等,均为1/n
ST.elem[0] = key
,引入它的mu1//升序
void BubbleSort(ElemType A[], int len){
for(int i = 0; i<len; i++){
//本趟是否进行了交换,有交换则赋值为true,然后继续进行下一趟;没有交换则排序结束
bool flag = false;
for(int j = 0; j<len-i; j++){
if(A[j]>A[j+1]){
swap(A,j,j+1);
flag = true;
}//if-end
}//2for-end
if(!flag) break;
}//1for-end
}
有序序列A[1…i-1] | | A[i] | | 无序序列A[i+1…n] |
---|
//A[0]作为插入排序暂存元素的位置,当作哨兵。
//实际数组的位置为1~n,实际数组长度为n-1。
void InsertSort(ElemType A[], int len){
for(int i = 2; i<=len; i++){
if(A[i] < A[i-1]){
A[0] = A[i]; //设置哨兵
for(int j = i-1; A[0]<A[j]; j--) A[j+1] = A[j]; //注意内层for循环的结束条件是元素与哨兵的比较
A[j+1] = A[0];
}
}
}
void InsertSort(ElemType A[], int len){
}
void SelectSort(ElemType A[], int len){
for(int i = 0; i<len-1; i++){
int min = i; //min记录最小元素的下标
for(int j = i+1; j<len; j++){
if(A[j]<A[min]) min = j;
}
if(min != i) swap(A,i,min); //注意这个判断if
}
}
void swap(ElemType A[], int a, int b){
ElemType temp = A[a];
A[a] = A[b];
A[b] = temp;
}
//A[0]作为二三层for循环的插入排序暂存元素的位置,但不是哨兵。
//实际数组的位置为1~n,实际数组长度为n-1。
void ShellSort(ElemType A[], int n){
for(int stepLen = n/2; stepLen>=1; stepLen/=2){
//第一层for循环用于控制步长stepLen的长度
for(int i = stepLen+1; i<=n; ++i){
//第二层for循环相当于插入排序的外层循环
//i首先指向待排序序列的第二个元素,因为插入排序中第一个元素自己相当于一个有序数组
if(A[i] < A[i-stepLen]){
for(int j = i-stepLen; j>0 && A[0] <A[j]; j -= stepLen){
//第三层for循环相当于插入排序的内层循环
A[j+stepLen] = A[j];
}//3for-end
A[j+stepLen] = A[0];
}//if-end
}//2for-end
}//1for-end
}//ShellSort-end
void MergeSort(ElemType A[], int low, int high){
if(low<high){
//int mid = (high-low+1)/2; 要的是mid的index!!所以应该是加法后除以2
int mid = (low+high)/2;
MergeSort(A,low,mid);
MergeSort(A,mid+1,high);
Merge(A,low,mid,high);
}
}
void Merge(ElemType A[], int low, int mid, int high){
//需要建立一个辅助数组,本可以只建立high-low+1这么长的数组即可,但是为了统一与A的下标,所以建立与A一样大的数组
ElemType *B = new ElemType[sizeof(A)];
//先把A的全部复制到B
for(int i = low; i<=high; i++) B[i]=A[i];
//两个有序合并成一个有序!!!
for(int i = low, j = mid+1, k = low; i<=mid && j<=high; k++){
if(B[i]<=B[j]){
//选出当前两个有序表中较小的元素,将其放到A
//这里如果写成 if(B[i]
A[k] = B[i];
i++;
}
else{
A[k] = B[j];
j++;
}
}//for-end
while(i<=mid) {A[k] = B[i]; i++; k++; } //可以简写成-> while(i<=mid) A[k++] = B[i++];
while(j<=high) {A[k] = B[j]; j++; k++; } //可以简写成-> while(j<=high) A[k++] = B[j++];
}
void QuickSort(ElemType A[], int low, int high){
if(low<high){
int pivotIndex = Partition(A,low,high);
QuickSort(A,low,piovtIndex-1);
QuickSort(A,piovtIndex+1,high);
}
}
int Partition(ElemType A[], int low, int high){
int piovt = A[low];
while(low<high){
while(low<high && A[high]>=piovt) high--;
A[low] = A[high];
while(low<high && A[low]>=piovt) low++;
A[high] = A[low];
}//while-end
A[low] = piovt;
return low;
}
//或许Partition函数这样写也是一样的,且更容易理解
int Partition(ElemType A[], int low, int high){
while(low<high){
while(low<high && A[high]>=A[low]) high--;
swap(ElemType A[],low,high);
while(low<high && A[high]>=A[low]) low++;
swap(ElemType A[],low,high)
}//while-end
return low;
}
void swap(ElemType A[], int a, int b){
ElemType temp = A[a];
A[a] = A[b];
A[b] = temp;
}
//A[0]作为插入排序暂存元素的位置,不是哨兵。
//实际数组的位置为1~n,实际数组长度为len=n-1。
//建立初始堆
void BuildMaxHeap(ElemType A[],int len){
for(int i = len/2; i>0; i--){
HeadAdjust(A,i,len);
}
}
void HeadAdjust(ElemType A[], int k, int len){
A[0] = A[k];
for(int i = 2*k; i<=len; i *= 2){
if(i<len && A[i=1]>A[i]){
i++;
}
else if(A[0]>A[i]) break;
else{
A[k] = A[i];
k = i;
}
}
A[k] = A[0]; //被筛选的节点放入最终位置
}
//堆排序
void HeapSort(ElemType A[], int len){
BuildMaxHeap(A,len);
for(int i = 1; i<=len; i++){
swap(A,1,len+1-i);
HeadAdjust(A,1,len-i);
}
}
void swap(ElemType A[], int a, int b){
ElemType temp = A[a];
A[a] = A[b];
A[b] = temp;
}