The data structure part of 985 postgraduate entrance examination landing (very complete, grasp the key points)

Data Structure of Kao Yan

Zhou Bo(Suzhou University of Science and Technology)

Email:xh_zhoubo@163.com QQ:2364339378

The main kingly code style is too messy (I doubt it was typed by one person, I unified it)

Where there are problems, please comment ~ reference: kingcraft + some algorithm templates

The linear table should mainly investigate the algorithm, either double pointer or divide and conquer. If it doesn't work, it's violence. I mainly practice the specification of the linked list

Therefore, it mainly arranges the key code questions of tree (the top priority), graph and string

The description idea of the postgraduate entrance examination code is also very important. Otherwise, the marking teacher may not understand... Give a low score

1. Tree [later focus on the topic of recursive thought]

Binary tree

1.1 it is known that a binary tree is stored according to the sequential structure, and an algorithm is designed to find the value of the nearest common ancestor of the two nodes numbered i and j respectively.

First, we know that the parent node number of any node i in the binary tree is i/2

1) If i > j, the level of i is greater than or equal to that of j. the parent node number of node i is i/2

If i/2=j, node i/2 is the nearest common ancestor of original node i and node j; If i/2 ≠ \neq  = j, then let i=i/2, that is, take the parent node of the node i as the starting point and search recursively

2) If J > i, the level of J is greater than or equal to that of i. the parent node number of node j is j/2

If j/2=j, node j/2 is the nearest common ancestor of original node i and node j; If j/2 ≠ \neq  = i, then j=j/2, ibid

ElemType SearchCommAncestor(SqTree T,int i, int j){
    if(T[i]!='#'&&T[j]!='#'{/ / node exists
        while(i!=j){
            if(i>j) i/=2;
            else j/=2;
        }
        return T[i];
    }
}
1.2 recursive writing - first order traversal (left and right roots), middle order traversal (left and right roots), and second order traversal (left and right roots) [many topics in the postgraduate entrance examination are extended from here]
//Each node is accessed only once, which is O(n)
//Worst case: a binary tree is a single tree with n nodes and depth n, space: O(n)
//Preorder traversal 
void PreOrder(BiTree T){
    if(T!=null){
        visit(T->data);
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}

//Medium order traversal
void InOrder(BiTree T){
    if(T!=null){
        InOrder(T->lchild);
        visit(T->data);
        InOrder(T->rchild);
    }
}

//Postorder traversal
void PostOrder(BiTree T){
    if(T!=null){
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        visit(T->data);
    }
}
1.3 non recursive writing of the above three Traversals

Preorder traversal non recursive:

On the basis of middle order traversal, you only need to put the access node operation in front of the stack operation

void InOrder(){
    InitStack(S);
    BiTree p=T;
    while(p||!IsEmpty(S)){
        if(p){
            visit(p->data);Push(S,p);
            p=p->lchild;
        }
        else {
            Pop(S,p);
            p=p->rchild;
        }
    }
}

Medium order traversal non recursive:

1) Stack the left child along the root in turn until the left child is empty (indicating that a node that can be output has been found)

2) Stack top element out of stack access: if the right child is not empty, execute 1); if the right child is empty, continue to execute 2)

void InOrder(){
    InitStack(S);
    BiTree p=T;//p is the traversal pointer
    while(p||!IsEmpty(S)){
        if(p){
            Push(S,p);
            p=p->lchild;
        }
        else {
            Pop(S,p);visit(p->data);
            p=p->rchild;
        }
    }
}

Postorder traversal is non recursive: [it can be used to find the path from the root to a node or the nearest common ancestor of two nodes]

1) Stack the left child along the root until the left child is empty

2) Read stack top element: if its right child is not empty and has not been accessed, turn the right subtree to execute 1); otherwise, the stack top element is out of the stack and accessed

Step 2) it is necessary to distinguish whether to return from the left subtree or the right subtree when returning, so set an auxiliary pointer r to point to the recently accessed node

void PostOrder(){
    InitStack(S);
    BiTree p=T;
    r=NULL;
    while(p||!IsEmpty(S)){
        if(p){
            Push(S,p);
            p=p->lchild;
        }
        else {
           GetTop(S,p);
           if(p->rchild&&p->rchild!=r)p=p->rchild;//Right subtree to execute 1)
             pop(S,p);
             visit(p->data);
             r=p;//Record the most recently visited nodes
             p=NULL;//Reset p pointer after node access
           }
        }
    }
}
1.4 hierarchical traversal algorithm (BFS in essence, maintained by queue)
void LevelOrder(BiTree T){
    InitQueue(Q);
    BiTree p;
    EnQueue(Q,T);
    while(!IsEmpty(Q)){
        DeQueue(Q,p);
        visit(p);
        if(p->lchild!=NULL) EnQueue(Q,p->lchild);
        if(p->rchild!=NULL) EnQueue(Q,p->rchild);   
    }
 }

Traversal is the basis of various operations of binary tree. Various operations can be carried out on nodes in the traversal process. For example, for a known tree, find the parents of nodes, find the child nodes of nodes, find the depth of binary tree, find the number of leaf nodes of binary tree, judge whether the two binary trees are the same, etc

1.5 try to give the top-down and right to left hierarchical traversal algorithm of binary tree

Using the original hierarchical traversal algorithm, each node is put into the stack at the same time of leaving the queue, and then access from the top of the stack after all nodes are put into the stack

void InvertLevelOrder(BiTree T){
	Stack S;Queue Q;
	if(T!=NULL){
		InitStack(S);
		InitQueue(Q);
		EnQueue(Q,T);
		while(!IsEmpty(Q)){
			Dequeue(Q,p);
			Push(S,p);//The changes are mainly here
			if(p->lchild) EnQueue(Q,p->lchild);
			if(p->rchild) EnQueue(Q,p->rchild); 
		}
		while(!IsEmpty(S)){
			Pop(S,p);
			visit(p->data); 
		}
	} 
}
1.6 assuming that the binary tree adopts the binary linked list storage structure, a non recursive algorithm is designed to calculate the height of the binary tree

Because the level traversal is to output the elements of each layer before traversing the next layer, we can increase the height by + 1 after traversing the last node of each layer

Set the last pointer only to the rightmost node of the current layer. Each time the layer traverses out of the queue, compare it with last. If the two are equal, the number of layers + 1, and let last point to the rightmost node of the next layer until the traversal is completed. The level value is the height

int Btdepth(BiTree T){
	if(!T) return 0;//Tree empty, height 0
	int front=-1,rear=-1;//Team leader and team tail
	int last=0,depth=0;
	BiTree Q[MaxSize];
	Q[++rear]=T; 
	BiTree p;
	while(front<rear){
		p=Q[front++];
		if(p->lchild) Q[rear++]=p->lchild;
		if(p->rchild) Q[rear++]=p->rchild;
		if(front==rear){
			depth++;
			last=rear;
		} 
	} 
	return depth;
}

Of course, recursion can also be used to realize the following:

int Btdepth(BiTree T){
	if(T==NULL) return 0;
	int ldepth = Btdepth(T->lchild);
	int rdepth = Btdepth(T->rchild);
	return max(ldepth+1,rdepth+1); 
} 

If it is to find the number of nodes in a layer, the number of nodes in each layer, the maximum width of the tree, etc., my implementation is:

int width[MaxSize],num=0,MaxWidth=-1;
int Btdepth(BiTree T){
	if(!T) return 0;//Tree empty, height 0
	int front=-1,rear=-1;//Team leader and team tail
	int last=0,depth=0,num;
	BiTree Q[MaxSize];
	Q[++rear]=T; 
	BiTree p;
	while(front<rear){
		p=Q[front++];
		if(p->lchild) Q[rear++]=p->lchild,num++;
		if(p->rchild) Q[rear++]=p->rchild,num++;
		if(front==rear){
			//If it is to find the number of nodes in each layer or a layer 
	 		width[depth++]=num;
	 		//If yes, find the maximum width of the tree
			MaxWidth=max(num,MaxWidth);
			last=rear;
			num=0;
		} 
	} 
	return depth;
	//return MaxWidth
}
1.7 suppose that the values of each node in a binary tree are different from each other, and its preorder sequence and middle order traversal algorithm exist in two one-dimensional arrays A[1... n] and B[1... n], respectively. Try to write an algorithm to establish the linked list of the binary tree

1) The root node of the tree is determined according to the preorder sequence

2) According to the root node, which nodes are included in the left and right subtree nodes of the binary tree are divided in the middle order sequence, and the root node of the subtree is determined in the order in the pre order sequence, that is, go back to step 1). This is repeated until each subtree has only one node (the root node of the tree)

BiTree PreInCreat(ElemType A[],ElemType B[],int l1,int h1,int l2,int h2){
	//L1 and H1 are the subscripts of the first and last nodes of the preorder, and L2 and H2 are the subscripts of the first and last nodes of the middle order
	//During initial call, l1=l2=1,h1=h2=n;
	root (BiTNode*)malloc(sizeof(BiTNode));
	root->data=A[l1];
	int i;//Note that this is global variable
	for(i=l2;B[i]!=root->data;i++);
	llen=i-l2,rlen=h2-i;
	if(llen) root->lchild=PreInCreat(A,B,l1+1,l1+llen,l2,l2+llen-1);
	else root->lchild=NULL;
	if(rlen) root->rchild=PreInCreat(A,B,h1-rlen+1,h1,h2-rlen+1);
	else root->rchild=NULL;
	return root;
} 
1.8 the binary tree is stored in the form of binary linked list, and an algorithm is written to judge whether a given binary tree is a complete binary tree

According to the definition of complete binary tree, a complete binary tree with n nodes corresponds to the nodes numbered from 1 to N in the full binary tree one by one

Using hierarchical traversal, all nodes are added to the queue (including empty nodes). When encountering empty nodes, check whether there are non empty nodes. If so, the binary tree is not a complete binary tree

bool isComplete(BiTree T){
	InitQueue(Q);
	if(!T) return 1;//An empty tree is a full binary tree 
	EnQueue(Q,T);
	while(!IsEmpty(Q)){
		DeQueue(Q,p);
		if(p) EnQueue(Q,p->lchild),EnQueue(Q,p->rchild);
		else {
			while(!IsEmpty(Q)){
				DeQueue(p);
				if(p) return 0;//If the node is not empty, the binary tree is incomplete binary tree 
			}
		} 
	} 
} 
1.9 assuming that the binary tree is stored in the binary linked list storage structure, try to design an algorithm to calculate the number of all double branch nodes of a given binary tree

Double branch node: a node with both left and right children

The recursive model is as follows:

if b=NULL f(b)=0;

if *b is a double branch node, f (b) = f (B - > lchild) + F (B - > rchild) + 1

else f(b)=f(b->lchild)+f(b->rchild)

int cntDsonNodes(BiTree T){
	if(b==NULL) return 0;
	else if(b->lchild!=NULL&&b->rchild!=NULL)
		return cntDsonNodes(T->lchild)+cntDsonNodes(T->rchild)+1;
	else
		return cntDsonNodes(T->lchild)+cntDsonNodes(T->rchild);
}
1.10 let the tree be a binary tree stored in chain structure. Try to write a function to exchange the left and right children of all nodes in tree B

1) First, the left and right subtrees of the left child of node b are exchanged

2) Then exchange the left and right subtrees of the right child of node b

3) Finally, the left and right subtrees of node b are exchanged

void Swap(BiTree T){
	if(T){
		swap(T->lchild);
		swap(T->rchild);
		temp=b->lchild;
		b->lchild=b->rchild;
		b->rchild=temp;
	}
} 
1.11 assuming that the binary tree is stored in a binary linked list structure, an algorithm is designed to find the value of the K (1 < = k < = number of nodes in the binary tree) node in the preorder traversal sequence

Set a global variable I to record the sequence number of the visited node. Its initial value is the sequence number of the root node in the sequence, i.e. 1

When the binary tree T is empty, the special character '#' is returned;

When i==k, it means that the node satisfying the condition is found, and T - > data is returned;

When i ≠ \neq When = k, search recursively in the left subtree. If found, return the value. Otherwise, continue to search recursively in the right subtree and return the result

int i=1;
ElemType PreNode(BiTree T,int k){
	if(b==NULL) return '#';
	if(i==k) return b->data;
	i++;
	ch=PreNode(T->lchild,k);
	if(ch!='#') return ch;
	ch=PreNode(T->rchild,k);
	if(ch!='#') return ch;
} 

What if we find the k in the middle order and the k in the back order?

1.12 set up a full binary tree (all node values are different), know that its pre sequence is pre, and design an algorithm to find the post sequence

For a general binary tree, another traversal sequence can not be determined only according to the pre order or post order, but for a full binary tree, the left and right subtrees of any node have the same number of nodes; At the same time, the first node of the pre sequence is the last node of the post sequence, so the recursive model for converting the pre sequence pre[l1... h1] into post[l2... h2] is as follows:

f(pre,l1,h1,post,l2,h2) = do nothing, HL < L1

f(pre,l1,h1,post,l2,h2) post[h2]=pre[l1] other cases

Take the middle position half=(h1-l1)/2;

Convert the left subtree of pre[l1+1,l1+half] into post[l2,l2+half-1], that is, f(pre,l1+1,l1+half,post,l2,l2+half-1);

The right subtree of pre[l1+half+1,h1] is transformed into post[l2+half,h2-1], that is, f(pre,l1+half+1,h1,l2+half,h2-1)

void PreToPost(ElemType pre[],int l1,int h1,ElemType post[],int l2,int h2){
	int half;
	post[h2]=pre[h1];
	half=(h1-l1)/2;
	PreToPost(pre,l1+1,l1+half,post,l2,l2+half-1);//Transform left subtree 
	PreToPost(pre,l1+half+1,h1,post,l2+half,h2-1);//Transform right subtree 
}
1.13 design an algorithm to connect the leaf nodes of the binary tree into a single linked list from left to right, and the header pointer is head. The binary tree is stored as a binary linked list, and the pointer field of the leaf node is used to store the single linked list pointer when linking

The leaf nodes are accessed from left to right by preorder, middle order and post order traversal. Here, the middle order traversal is taken as an example

Set the precursor node pointer pre, which is initially null. The first leaf node is pointed by the pointer head. When traversing the leaf node, point its precursor's rchild pointer to it, and the last pointer is null

//Time: O(n), space: O(n)
LinkedList head,pre=NULL;
LinkedList InOrder(BiTree T){
	if(T){
		InOrder(T->lchild);
		if(T->lchild==NULL&&T->rchild==NULL){//leaf 
			if(pre==NULL){
				head=T;
				pre=T;
			}
			else{
				pre->rchild=T;
				pre=T;
			}
		} 
		InOrder(T->rchild);
		pre->rchild=NULL;
	}
	return head;
}
1.14 try to design an algorithm to judge whether two binary trees are similar. The so-called similarity of binary trees T1 and T2 means that both T1 and T2 are empty binary trees or have only one root node; Or the left subtree of T1 and T2 are similar, and the right subtree of T1 and T2 are similar

Recursion: if T1 and T2 are empty trees, they are similar; If one is empty and the other is not empty, it must be different; Otherwise, recursively compare whether their left and right subtrees are similar. The definition of recursive function is as follows:

1)if T1T2NULL f(T1,T2)=1;

2)else if T1NULL || T2NULL f(T1,T2)=0;

3)else f(T1,T2)=f(T1->lchild,T2->lchild) && f(T1->rchild,T2->rchild)

int IsSimilar(BiTree T1,BiTree T2){
	int leftS,rightS;
	if(T1==NULL&&T2==NULL) return 1;
	else if(T1==NULL||T2==NULL) return 0;
	else {
		leftS=IsSimilar(T1->lchild,T2->rchild);
		rightS=IsSimilar(T1->rchild,T2->rchild);
		return leftS&&rightS;
	}
} 
1.15 the weighted path length (WPL) of a binary tree is the sum of the weighted path lengths of all leaf nodes in the binary tree. Given a binary tree T, it is stored in a binary linked list, and the node structure is left,weight,right. The weight field of the leaf node stores the non negative weight of the node. Set root as the pointer to the root node of T, please design the WPL algorithm of T

Using preorder traversal, wpl is recorded with a static variable, and the depth of each node is passed as a recursive parameter

1) If the node is a leaf node, the product of variable + depth and weight of the node

2) If the node is a non leaf node, when the left subtree is not empty, call the recursive algorithm for the left subtree, and if the right subtree is not empty, call the recursive algorithm for the right subtree. The depth parameters are the depth parameters of the node + 1

3) Finally, the calculated wpl is returned

typedef struct BiTNode{
	int weight;
	struct BiTNode *lchild,*rchild;	
}BiTNode,*BiTree;

int WPL(BiTree root){
	return wpl_PreOrder(root,0);
} 

int wpl_PreOrder(BiTree root, int depth){
	static int wpl=0;
	if(root->lchild==NULL&&root->rchild==NULL)
		wpl+=depth*root->weight;
	if(root->lchild!=NULL)
		wpl_PreOrder(root->lchild,depth+1);
	if(root->rchild!=NULL)
		wpl_PreOrder(root->rchild,depth+1);
	return wpl; 
}

Trees and forests

1.16 program to calculate the number of leaf nodes of the forest stored in the child brother representation
typedef struct node{
	Elemtype data;
	struct node *fch,*nsib;
}*Tree;

int Leaves(Tree T){
	if(T==NULL) return 0;
	if(T->fch==NULL) return 1+Leaves(T->nsib);
	else return Leaves(T->fch)+Leaves(T->nsib); 
}
1.17 with the linked list of children's brothers as the storage structure, please design a recursive algorithm to find the depth of the tree
int Height(CSTree T){
	int hc,hs;
	if(T==NULL)return 0;
	else {
		hc=Height(T->lchild);
		hs=Height(T->rchild);
		if(hc+1>hs) return hc+1;
		else return hs;
	}
}

Application of binary tree (binary sort tree (BST) and balanced binary tree (AVL))

1.18 try to write an algorithm to judge whether a given binary tree is a binary sort tree

For a binary sort tree, the order traversal sequence is an increasing order sequence. Therefore, if the middle order traversal of a given binary tree can always keep the former value smaller than the latter value, it means that the binary tree is a binary sort tree

ElemType pre=-1e9;//Save the value of the current node precursor 
int JudgeBST(BiTree T){
	int ans1,ans2;
	if(T==NULL)return 1;
	else{
		ans1=JudgeBST(T->lchild);
		if(ans1==0||pre>=T->data) return 0;
		pre=T->data;//Save keyword of current node
		ans2=JudgeBST(T->rchild);
		return ans2;
	}
} 
1.19 design an algorithm to find the level of the specified node in a given binary sort tree

In the binary sort tree, searching once drops one level. Therefore, the number of times to find the node is the level of the node in the binary sort tree

int Level(BiTree T, BSTNode *p){
	int cnt=0;
	BiTree t=T;
	while(T!=NULL){
		cnt++;
		while(t->data!=p->data){
			if(p->data<t->data) t=t->lchild;
			else t=t->rchild;
			cnt++;
		}
	} 
	return cnt;
}
1.20 using the idea of binary tree traversal, write an algorithm to determine whether a binary tree is a balanced binary tree

Set the balance flag of the binary tree as balance, and the flag returns whether the binary tree T is a balanced binary tree; h is the height of the binary tree

1) If T is empty, the height is 0 and balance = 1;

2) If T has only root node, the height is 1,balance=1;

3) Otherwise, the left and right subtrees of T are recursively calculated, and the height and balance mark of the left and right subtrees are returned. The height of T is the height of the highest subtree + 1. If the height difference between the left and right subtrees is > 1, then balance=0; If the height difference between the left and right subtrees is less than or equal to 1, and the left and right subtrees are balanced, balance=1, otherwise balance=0

int Judge_AVL(BiTree T,int &balance,int &h){//Balance is the balance mark of binary tree 
	int bl,br,hl,hr;//Balance mark and height of left and right subtrees
	if(T==NULL) h=0,balance=1,return balance;
	else if(T->lchild==NULL&&T->rchild==NULL)h=1,balance=1,return balance;
	else{
		Judge_AVL(T->lchild,bl,h1);
		Judge_AVL(T->rchild,br,hr);
		h=(hl>hr?hl:hr)+1;
		if(abs(hl-hr)<2) balance=bl&&br;
		else balance=0;
	}
	return balance; 
}
1.21 design an algorithm to output all keywords with values not less than k in the binary sort tree from large to small

In a binary sort tree, the bottom left node is the node with the smallest keyword, and the bottom right node is the node with the largest keyword. As long as these two nodes are found, there is no need to compare keywords

KeyType MinKey(BSTNode *T){
	while(T->lchild!=NULL) T=T->lchild;
	return T->data;
} 

KeyType MaxKey(BSTNode *T){
	while(bt->rchild!=NULL) T=T->rchild;
	return T->data;
} 

The binary tree pointers in the above code are all represented by T, and the following is uniformly represented by bt ~ it feels that bt is more vivid. As for the final choice, it depends on the reader's preference

1.22 output all keywords with value not less than k in binary sort tree from large to small

In the binary sort tree, all the node values of the right subtree are greater than the root node value, and all the nodes in the left subtree are less than the root node value. In order to output from large to small, first traverse the right subtree, then access the root node, and then traverse the left subtree

void Output(BSTNode *bt,KeyType k){
	if(bt==NULL)return;
	if(bt->rchild!=NULL) Output(bt->rchild,k);
	if(bt->data>=k) printf("%d",bt->data);
	if(bt->lchild!=NULL) Output(bt->lchild,k);
}
1.23 write a recursive algorithm to find the element with the smallest K (1 < = k < = n) on a randomly established binary sort tree with n nodes, and return the pointer to the node. It is required to O(log2n). In each node in the binary sort tree, in addition to data, lchild and rchild, add a count member to save the number of nodes in the subtree with this node as the root

The root node of the binary sort tree is set to * bt

  • Bt - > lchild is null

    1)k==1, i.e. * bt is the element with the smallest k, and the search is successful

    2)k$\neq, then the k-th smallest element must be in the right subtree of * bt

  • Bt - > lchild non empty

    1) bt - > lchild - > count = = k-1, i.e. * bt is the k-th smallest element. The search is successful

    2) bt - > lchild - > count > k-1, then the k-th smallest element must be found in the left subtree of * bt and continue to the left subtree of * bt

    3) bt - > lchild - > count < k-1, the element with the smallest K must be in the right subtree of * bt, and continue to search in the right subtree of * bt

    The search rules of the left and right subtrees are the same

    BSTNode *Search_small(BSTNode *bt,int k){
    	if(k<1||k>bt->count) return NULL;
    	if(bt->lchild==NULL){
    		if(k=1) return bt;
    		else return Search_small(k-1);
    	}
    	else{
    		if(bt->lchild->count==k-1) return bt;
    		if(bt->lchild->count>k-1) 
    			return search_Small(bt->lchild,k);
    		if(bt->lchild->count<k-1) 
    			return search_Small(bt->rchild,k-(bt->lchild->count+1));
    	} 
    } 
    

    Other examples: recursive implementation

    1) Count the number of nodes with moderate 1 in binary tree

    2) Count the number of nodes with moderate 2 in binary tree

    3) Count the number of nodes with 0 in binary tree

    4) Statistical height of binary tree

    5) Statistical width of binary tree

    6) Delete all leaf nodes from the binary tree

    7) Calculate the hierarchy of the specified node * p

    8) Calculate the maximum element value of each node in the binary tree

    9) Exchange two children of each node in a binary tree

    10) The data values of all nodes in a binary tree and the hierarchy of nodes are output in order

2. Graph [shortest path + minimum spanning tree]

2.1 simple Dijkstra [O(n^2+m)]

Key: every time a vertex is added to the set S, it may be necessary to modify the current shortest path length from the source point v0 to the vertex in the set V-S

Time complexity is O(n^2+m), n Indicates the number of points, m Represents the number of sides
int g[N][N];  // Store each edge
int dist[N];  // Store the shortest distance from point 1 to each point
bool st[N];   // Store whether the shortest circuit of each point has been determined

// Find the shortest circuit from point 1 to point n. if it does not exist, return - 1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    for (int i = 0; i < n - 1; i ++ )
    {
        int t = -1;     // Find the point with the smallest distance among the points where the shortest path has not been determined
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        // Update the distance of other points with t
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);
        st[t] = true;
    }
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
2.2 heap optimized version Dijkstra [O(mlogn)] (after all, heap optimization + a large amount of code is used, so it's not easy to pass the exam, and it's not seen in the later stage)
//Time complexity O(mlogn), n represents the number of points, and m represents the number of edges
typedef pair<int, int> PII;

int n;      // Number of points
int h[N], w[N], e[N], ne[N], idx;       // The adjacency table stores all edges
int dist[N];        // Store the distance from all points to point 1
bool st[N];     // Is the shortest distance to store each point determined

// Find the shortest distance from point 1 to point n. if it does not exist, return - 1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});      // first storage distance, second storage node number
    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();
        int ver = t.second, distance = t.first;
        if (st[ver]) continue;
        st[ver] = true;
        for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > distance + w[i])
            {
                dist[j] = distance + w[i];
                heap.push({dist[j], j});
            }
        }
    }
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
2.3 Floyd[O(n^3)]
The time complexity is O(n^3), n Represents the number of points
 initialization:
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= n; j ++ )
            if (i == j) d[i][j] = 0;
            else d[i][j] = INF;

// After the algorithm, d[a][b] represents the shortest distance from a to B
void floyd()
{
    for (int k = 1; k <= n; k ++ )
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
2.4 finding the minimum spanning tree with simple Prim

Key: continuously select the vertex closest to the vertex set in the current T, and add the vertex and corresponding edge to T. after each operation, the number of vertices and edges of T + 1

The time complexity is O(n^2+m), n Indicates the number of points, m Represents the number of sides
int n;      // n represents the number of points
int g[N][N];        // Adjacency matrix, storing all edges
int dist[N];        // Stores the distance from other points to the current minimum spanning tree
bool st[N];     // Stores whether each point is already in the spanning tree
// If the graph is not connected, inf (the value is 0x3f3f3f3f) is returned; otherwise, the sum of tree edge weights of the minimum spanning tree is returned
int prim()
{
    memset(dist, 0x3f, sizeof dist);
    int res = 0;
    for (int i = 0; i < n; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        if (i && dist[t] == INF) return INF;
        if (i) res += dist[t];
        st[t] = true;
        for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
    }
    return res;
}
2.5 Kruskal finds the minimum spanning tree (the code feels that it will not take into account the large amount of code + it will not be seen in the later stage of joint search)

Key: each vertex forms a connected component, and continuously selects the edge with the smallest weight that has not been selected at present. When adding, pay attention not to form a "ring"

The time complexity is O(mlogm), n Indicates the number of points, m Represents the number of sides
int n, m;       // n is the number of points and m is the number of sides
int p[N];       // Parent node array of the join query set

struct Edge     // Storage edge
{
    int a, b, w;

    bool operator< (const Edge &W)const
    {
        return w < W.w;
    }
}edges[M];

int find(int x)     // Core operation of parallel query set
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int kruskal()
{
    sort(edges, edges + m);
    for (int i = 1; i <= n; i ++ ) p[i] = i;    // Initialize and query set
    int res = 0, cnt = 0;
    for (int i = 0; i < m; i ++ )
    {
        int a = edges[i].a, b = edges[i].b, w = edges[i].w;
        a = find(a), b = find(b);
        if (a != b)     // If two connected blocks are not connected, the two connected blocks are merged
        {
            p[a] = b;
            res += w;
            cnt ++ ;
        }
    }
    if (cnt < n - 1) return INF;
    return res;
}

3.KMP

// s [] is the long text, p [] is the pattern string, n is the length of s, and m is the length of p
 Find the of pattern string Next Array:
for (int i = 2, j = 0; i <= m; i ++ )
{
    while (j && p[i] != p[j + 1]) j = ne[j];
    if (p[i] == p[j + 1]) j ++ ;
    ne[i] = j;
}

// matching
for (int i = 1, j = 0; i <= n; i ++ )
{
    while (j && s[i] != p[j + 1]) j = ne[j];
    if (s[i] == p[j + 1]) j ++ ;
    if (j == m)
    {
        j = ne[j];
        // Logic after successful matching
    }
}

4.BFS example - hierarchy of nodes in the diagram

queue<int> q;
st[1] = true; // Indicates that point 1 has been traversed
q.push(1);

while (q.size())
{
    int t = q.front();
    q.pop();
    for (int i = h[t]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!st[j])
        {
            st[j] = true; // Indicates that point j has been traversed
            q.push(j);
        }
    }
}

Tags: C C++ Algorithm data structure

Posted on Sun, 31 Oct 2021 23:57:39 -0400 by bundyxc