1. 程式人生 > 資訊 >華為技術有限公司申請 “花瓣翻譯”商標,屬設計研究類

華為技術有限公司申請 “花瓣翻譯”商標,屬設計研究類

技術標籤:理論知識資料結構

- 初級資料結構

  • 1、連結串列、雙向連結串列

  • 定義連結串列:

struct LinkList {  
    int value;  
    LinkList *next;  
};  
  • 根據輸入建立單鏈表

將輸入的節點插入到連結串列頭部。

LinkList *BuildList() {  
    LinkList *head = NULL;  
    int data;  
    int i = 0;  
    while (scanf("%d", &data) != EOF) {  
        //scanf("%d", &data);++i;  
LinkList *new_node = (LinkList *)malloc(sizeof(LinkList)); if (NULL == new_node) { fprintf(stderr, "malloc failed"); return head; } new_node->value = data; if (head == NULL) { new_node->next = NULL
; head = new_node; } else { new_node->next = head; head = new_node; } } return head; }
  • 插入

//在連結串列頭部插入節點  
LinkList *InsertToHead(int value, LinkList *head) {  
    LinkList *new_node = (LinkList *)malloc(sizeof
(LinkList)); if (new_node == NULL) { fprintf(stderr, "malloc failed"); return head; } new_node->value = value; new_node->next = NULL; if (head == NULL) { head = new_node; } else { new_node->next = head; head = new_node; } return head; }
//連結串列尾部插入節點
LinkList *InsertToTail(int value, LinkList *head) {
	LinkList *new_node = (LinkList *)malloc(sizeof(LinkList));
	if (new_node == NULL) {
		fprintf(stderr, "malloc failed");
		return head;
	}
	new_node->value = value;
	new_node->next = NULL;

	if (head == NULL)
		head = new_node;
	else {
		LinkList *pnode = head;
		while (pnode->next != NULL)
			pnode = pnode->next;
		pnode->next = new_node;
	}
	return head;
}
  • 刪除

//刪除某節點  
LinkList *DeletebyValue(int value, LinkList* head) {  
    if (head == NULL)  
        return head;  
    LinkList *pToDelete = NULL;  
    if (head->value == value) {  
        pToDelete = head;  
        head = head->next;  
    }  
    else {  
        LinkList *p = head;  
        while (p->next != NULL && p->next->value != value)  
            p = p->next;  
        if (p->next != NULL) {  
            pToDelete = p->next;  
            p->next = pToDelete->next;  
        }  
    }  
    if (pToDelete != NULL) {  
        free(pToDelete);  
        pToDelete = NULL;  
    }  
    return head;  
}  
  • 求單鏈表中結點的個數

注意檢查連結串列是否為空。時間複雜度為O(n)。該操作不用特意檢查連結串列是否為空,如下程式碼,連結串列為空會返回0。

unsigned int Length(LinkList *head) {  
    unsigned int length = 0;  
    LinkList *p = head;  
    while (p) {  
        ++length;  
        p = p->next;  
    }  
    return length;  
}  
  • 列印連結串列元素

//列印單鏈表  順序 
void PrintList(LinkList *head) {  
    LinkList *p = head;  
    while (p) {  
        printf("%d ", p->value);  
        p = p->next;  
    }  
    printf("\n");  
}  
//逆序列印單鏈表:非遞迴  
void RPrintList(LinkList* head) {  
    if (NULL == head)  
        return;  
    stack<int> list_stack;  
    while (head) {  
        list_stack.push(head->value);  
        head = head->next;  
    }  
    while (!list_stack.empty()) {  
        printf("%d ", list_stack.top());  
        list_stack.pop();  
    }  
    printf("\n");  
}  
  
//逆序列印單鏈表:遞迴  
void RPrintListRecursively(LinkList* head) {  
    if (NULL == head)  
        return;  
    else {  
        RPrintListRecursively(head->next);  
        printf("%d ", head->value);  
    }  
}  

雙向連結串列是什麼

  • 2、佇列、單調佇列、棧、單調棧

  • 佇列:

遵循先進先出的原則(FIFO)的資料結構。

  • STL:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>

using namespace std;

int main() {
	queue <int> qu;
	int a;
	scanf("%d",&a);
	qu.push(a); //插入元素 
	if(!qu.empty()) { //判斷佇列是否為空 
		cout<<qu.size()<<endl; //輸出佇列中元素個數 
		cout<<qu.front(); //輸出隊首元素 
		qu.pop(); //彈出隊首元素 
	}
	return 0;
}
  • 手寫佇列:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

struct queue {
	int Q[500005],head,tail;
	queue() {
		head=0,tail=0;
	}
	void push(int a) {
		Q[++tail]=a;
		return ;
	}
	void pop() {
		head++;
		return ;
	}
	bool empty() {
		return head>=tail;
	}
	int front() {
		return Q[head+1];
	}
	int size() {
		if(head<=tail) return tail-head; 
	} 
};

int main() {
	queue qu;
	int a;
	scanf("%d",&a);
	qu.push(a); //插入元素 
	if(!qu.empty()) { //判斷佇列是否為空 
		cout<<qu.size()<<endl; //輸出佇列中元素個數 
		cout<<qu.front(); //輸出隊首元素 
		qu.pop(); //彈出隊首元素 
	}
	return 0;
}
  • 單調佇列:

給定一個佇列,維護三個操作。
1:將一個數x壓入佇列中。
2:求佇列中數的最大值。
3:彈出佇列尾的數。

這就要用到單調佇列。

在每次進入隊伍時,判斷當前元素與隊尾元素的大小關係,若小於隊尾元素,則隊尾不可能成為最小值,直接刪除即可。
每次查詢的答案一定在隊首位置。
由於每個元素至多進佇列和出佇列一次,時間複雜度為O(n)。

下面以Sliding Window為例

STL(用deque(雙端佇列))

#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>

using namespace std;
typedef pair<int,int> P;
#define maxn 1000000 + 10

deque<P> Q1;
deque<P> Q2;
int n,k;
int Min[maxn], Max[maxn];

int main() {
	while(~scanf("%d%d", &n, &k)) {
		while(!Q1.empty()) Q1.pop_back();
		while(!Q2.empty()) Q2.pop_back();
		int x;
		for(int i=1; i<=n; i++) {
			scanf("%d", &x);
			while(!Q1.empty() && Q1.back().first >= x) Q1.pop_back();
			Q1.push_back(P(x,i));
			if(i >= k) {
				while(!Q1.empty() && Q1.front().second <= i-k) Q1.pop_front();
				Min[i] = Q1.front().first;
			}
			while(!Q2.empty() && Q2.back().first <= x) Q2.pop_back();
			Q2.push_back(P(x,i));
			if(i >= k) {
				while(!Q2.empty() && Q2.front().second <= i-k) Q2.pop_front();
				Max[i] = Q2.front().first;
			}
		}
		for(int i=k; i<=n; i++)
			i == n ? printf("%d\n", Min[i]) : printf("%d ", Min[i]);
		for(int i=k; i<=n; i++)
			i == n ? printf("%d\n", Max[i]) : printf("%d ", Max[i]);
	}
	return 0;
}

手寫

#include <iostream>
#include <cstdio>
#include <algorithm>
#define MAXN 1000005

using namespace std;

struct s {
	int v,p;
	void f(int a,int b) {
		v=a,p=b;
	}
}Q1[MAXN],Q2[MAXN];

int h1,t1,h2,t2,Min[MAXN],Max[MAXN];
int n,k;

int main() {
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) {
		int x;
		scanf("%d",&x);
		while(h1<t1 && Q1[t1].v>=x) t1--;
		Q1[++t1].f(x,i);
		if(i>=k) {
			while(h1<t1 && Q1[h1+1].p<=i-k) h1++;
			Min[i]=Q1[h1+1].v;
		}
		while(h2<t2 && Q2[t2].v<=x) t2--;
		Q2[++t2].f(x,i);
		if(i>=k) {
			while(h2<t2 && Q2[h2+1].p<=i-k) h2++;
			Max[i]=Q2[h2+1].v;
		}
	}
	for(int i=k;i<=n;i++) printf("%d ",Min[i]);
	printf("\n");
	for(int i=k;i<=n;i++) printf("%d ",Max[i]);
	return 0;
}

  • 棧:

遵循先進後出的原則(FILO)的資料結構。

  • STL:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>

using namespace std;

int main() {
    stack <int> st;
    int a;
    scanf("%d",&a);
    st.push(a); //插入元素 
    if(!st.empty()) { //判斷棧是否為空 
        cout<<st.size()<<endl; //輸出棧中元素個數 
        cout<<st.top(); //輸出棧頂元素 
        st.pop(); //彈出棧頂元素 
    }
    return 0;
}
  • 手寫:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

struct stack {
	int a[23333],pos;
	stack() {
		pos=0;
	}
	void push(int x) {
		a[++pos]=x;
	}
	void pop() {
		pos--;
	}
	bool empty() {
		return !pos;
	}
	int top() {
		return a[pos];
	}
	int size() {
		return pos;
	}
};

int main() {
    stack st;
    int a;
    scanf("%d",&a);
    st.push(a); //插入元素 
    if(!st.empty()) { //判斷棧是否為空 
        cout<<st.size()<<endl; //輸出棧中元素個數 
        cout<<st.top(); //輸出棧頂元素 
        st.pop(); //彈出棧頂元素 
    }
    return 0;
}

  • 單調棧

  • 3、堆

STL多好用

#include <queue>
priority_queue <int> big_heap; //大根堆
priority_queue <int,vector<int>,greater<int> > small_heap; //小根堆
heap.top();
heap.push();
heap.pop();
heap.empty();
heap.size();

手寫:

 struct priority_queue {
	int a[23333],size;
	priority_queue() {
		size=0;
	}
	void push(int x) {
		a[++size]=x;
		int son=size,dad;
		while(son!=1) {
			dad=son>>1;
			if(a[dad]>a[son]) swap(a[dad],a[son]);
			son=dad;
		}
		return ;
	}
	int top() {
		return a[1];
	}
	void pop() {
		a[1]=a[size--];
		int dad=1,son=2;
		while(son<=size) {
			son=dad<<1;
			if(son<size && a[son]>a[son+1]) son++;
			if(a[dad]>a[son]) swap(a[son],a[dad]);
			dad=son;
		}
		return ;
	}
	bool empty() {
		return !size;
	}
}; 

- 基礎資料結構

  • 1、線段樹

二分的思想把區間內的點分成若干個線段然後處理問題,查詢和修改都是O(nlogn)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 1000005
#define ll long long
using namespace std;
inline ll read() {
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
ll a[maxn],sum[maxn<<2],col[maxn<<2];
void updata(ll rt) {
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void color(ll l,ll r,ll rt,ll c) {
	col[rt]+=c;
	sum[rt]+=c*(r-l+1);
}
void push_col(ll l,ll r,ll rt) {
	if(col[rt]) {
		ll m=(l+r)>>1;
		color(lson,col[rt]);
		color(rson,col[rt]);
		col[rt]=0;
	}
}
void build(ll l,ll r,ll rt) {
	if(l==r) {
		sum[rt] = a[l];
		return ;
	}
	ll m=(l+r)>>1;
	build(lson);
	build(rson);
	updata(rt);
}
ll query(ll l,ll r,ll rt,ll L,ll R) {
	if(L<=l && R>=r)return sum[rt];
	push_col(l,r,rt);
	ll ret=0;
	ll m=(l+r)>>1;
	if(L<=m) ret+=query(lson,L,R);
	if(m<R) ret+=query(rson,L,R);
	return ret;
}
void modify(ll l,ll r,ll rt,ll L,ll R,ll v) {
	if(L<=l && R>=r) {
		color(l,r,rt,v);
		return ;
	}
	push_col(l,r,rt);
	ll m=(l+r)>>1;
	if(L<=m) modify(lson,L,R,v);
	if(m<R) modify(rson,L,R,v);
	updata(rt);
}
ll n,m;
int main() {
	n=read(),m=read();
	for(ll i=1;i<=n;i++)a[i]=read();
	build(1,n,1);
	while(m--) {
		ll id=read();
		if(id==2) {
			ll x=read(),y=read();
			printf("%lld\n",query(1,n,1,x,y));
		}
		else {
			ll x=read(),y=read(),z=read();
			modify(1,n,1,x,y,z);
		}
	}
	return 0;
}

  • 2、樹狀陣列

字首和和差分的思想,利用二進位制,反正就是跳來跳去。反正背過就行。
就當存一下模板。

/*
1.將某一個數加上x
2.求出某區間每一個數的和
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#define MAXN 500005

using namespace std;

int a[MAXN],c[MAXN],n,m;

int lowbit(int x) {
	return x&(-x);
}

void modify(int p,int x) {
	while(p<=n) {
		c[p]+=x;
		p+=lowbit(p);
	}
	return ;
}

int sum(int p) {
	int sum=0;
	while(p) {
		sum+=c[p];
		p-=lowbit(p);
	}
	return sum;
}

int query(int l,int r) {
	return sum(r)-sum(l-1);
}

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),modify(i,a[i]);
	for(int i=1;i<=m;i++) {
		int id,x,y;
		scanf("%d%d%d",&id,&x,&y);
		if(id==1) modify(x,y); 
		else printf("%d\n",query(x,y));
	}
	return 0;
}
/*
1.將某區間每一個數數加上x
2.求出某一個數的和
*/
#include <iostream>
#include <cstdio>
#define maxn 500000+5

using namespace std;

int n,m,pre,c[maxn];

int lowbit(int x) {
	return x&(-x);
}

void modify(int pos,int x) {
	while(pos<=n) {
		c[pos]+=x;
		pos+=lowbit(pos);
	}
	return ;
}

int query(int pos) {
	int ans=0;
	while(pos>0) {
		ans+=c[pos];
		pos-=lowbit(pos);
	}
	return ans;
}

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++) {
		int x;
		scanf("%d",&x);
		modify(i,x-pre);
		pre=x;
	}
	while(m--) {
		int id;
		scanf("%d",&id);
		if(id==1) {
			int l,r,k;
			scanf("%d%d%d",&l,&r,&k);
			modify(l,k);
			modify(r+1,-k);
		} else {
			int pos;
			scanf("%d",&pos);
			printf("%d\n",query(pos));
		}
	}
	return 0;
}
  • ST表

給定一個數列a,O(nlogn)預處理,O(1)查詢數列在區間[l,r]的最值。
這裡介紹求最大值。

int st[N][K],a[N],log_2[N];
inline void ini_st(){
    log_2[1]=0;
    for(int i=2;i<=n;++i){
        log_2[i]=log_2[i-1];
        if((1<<log_2[i]+1)==i)
            ++log_2[i];
    }
    for(int i=n;i;--i){
        st[i][0]=a[i];
        for(int j=1;(i+(1<<j)-1)<=n;++j)
            st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
    }
}
inline int ask(int l,int r){
    int k=log_2[r-l+1];
    return max(st[l][k],st[r-(1<<k)+1][k]);
}

  • 並查集

貌似我在圖倫裡寫過了。

  • 帶權並查集


  • hash表

這個主要用於字串hash,整理字串的時候在寫吧。


  • 分塊

把問題分成許多(一般是根號n)塊,在塊中完成。時間複雜度為O(m根號n)

int belong[maxn],block,num,l[1000],r[1000];

int n,m;

void build() {
	block=sqrt(n);
	num=block;
	if(n%num)num++;
	for(int i=0;i<n;i++) {
		belong[i]=(i-1)/block;
	}
	for(int i=1;i<=num;i++) {
		l[i]=(i-1)*block;
		r[i]=i*block-1;
	}
	r[num]=n;
}