【c++提高1】二叉樹&二叉堆(萬字總結(jié))-創(chuàng)新互聯(lián)

大綱 一、二叉樹

二叉樹:1.二叉樹簡介
二叉樹:2.二叉樹的性質(zhì)
二叉樹:3.二叉樹的存儲
二叉樹:4.二叉樹的遍歷
二叉樹:5.求解先序、后序、層次遍歷序列
二叉樹:6.例題

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比樂清網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式樂清網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋樂清地區(qū)。費用合理售后完善,十載實體公司更值得信賴。 二、二叉堆

二叉堆:1.二叉堆簡介
二叉堆:2.二叉堆的插入操作
二叉堆:3.二叉堆的刪除堆頂操作
二叉堆:4.二叉堆復(fù)雜度分析
二叉堆:5.二叉堆代碼實現(xiàn)
二叉堆:6.優(yōu)先隊列
二叉堆:7.例題

二叉樹 一、二叉樹簡介 (1)簡介

二叉樹是N個節(jié)點的有限集合(N是自然數(shù)),當N=0時,那么就是一個空集合(叫空二叉樹)。
總的來講(N>0的情況),二叉樹就是由一個根節(jié)點和兩棵子樹組成的。
然而,從名字就可以看出來,二叉樹的每一個節(jié)點最多都只有兩棵子樹(分別稱為左子樹和右子樹)

(2)二叉樹的形態(tài)(類別) 按照節(jié)點數(shù)分類: 空二叉樹:

N=0
當這個集合的節(jié)點數(shù)為0時,稱為空二叉樹

只有一個根節(jié)點的二叉樹:

N=1
需要滿足的條件:集合的節(jié)點樹為1

根節(jié)點只有左子樹

需要滿足的條件:根節(jié)點沒有右子樹,只有左子樹

根節(jié)點只有右子樹

需要滿足的條件:根節(jié)點沒有左子樹,只有右子樹

根節(jié)點左子樹和右子樹都有

需要滿足的條件:根節(jié)點的左子樹和右子樹都有

按照形態(tài)分類:

常見二叉樹形態(tài) \color{blue}常見二叉樹形態(tài) 常見二叉樹形態(tài)

斜樹

從名字就可以看出來,斜樹是斜的,所以需要滿足條件:
所有的節(jié)點都只有左節(jié)點或者右節(jié)點
斜樹還分左斜樹和右斜樹,每個節(jié)點都只有左節(jié)點的叫做左斜樹,每個節(jié)點都只有右節(jié)點的叫做右斜樹

滿二叉樹

如果所有分支節(jié)點都存在左子樹和右子樹,并且所有葉子節(jié)點都在同一層上,這樣的二叉樹稱為滿二叉樹

完全二叉樹

如果編號為i(1 ≤ i ≤ N)的結(jié)點與同樣深度的滿二叉樹中編號為i的節(jié)點在二叉樹中位置完全相同,則這棵二叉樹稱為完全二叉樹。

二、二叉樹的性質(zhì) 性質(zhì)1:在二叉樹的第i層上至多有2^(i-1)個節(jié)點 證明:設(shè)d(i)表示第i層的大節(jié)點數(shù)

每個節(jié)點至多有兩個子節(jié)點:d(i)=d(i-1)*2
第一層是根節(jié)點,只有一個節(jié)點,所以:d(1)=1=2^(1-1)
第i層的大節(jié)點數(shù)d(i)=d(1)*2 ^ (i-1)=2 ^ (i-1)

性質(zhì)2:深度為k的二叉樹至多有2^k-1個節(jié)點 證明:設(shè)d(i)表示深度為i的二叉樹的大節(jié)點數(shù)

d(1)=1=2 ^ 1-1
d(2)=d(1)+2 ^ 1=2 ^ 1+2 ^ 1-1=2 ^ 2-1
d(3)=d(2)+2 ^ 2=2 ^ 2+2 ^ 2-1=2 ^ 3-1
d(k)=d(k-1)+2 ^ (k-1)=2 ^ (k-1)+2 ^ (k-1)-1=2 ^ k-1

性質(zhì)3:一棵二叉樹葉子節(jié)點數(shù)(設(shè)為n0)等于度為2的節(jié)點數(shù)(設(shè)為n2): 證明:

① 二叉樹中除了葉子節(jié)點外,剩下的節(jié)點要么度為1,要么度為2。(葉子節(jié)點度為0),
那么二叉樹的節(jié)點數(shù) n = n0 + n1 + n2(式子1)。
② 度為1的節(jié)點擁有1個孩子,度為2的節(jié)點擁有2個孩子,孩子結(jié)點總數(shù)為: n1+ 2n2 。
③ 二叉樹中,只有根節(jié)點不是孩子節(jié)點,所以: n = n1 + 2n2 + 1 (式子2 )。
根據(jù)式子1和式子2可知: n0 + n1 + n2 = n1 + 2n2 + 1 ? n0 = n2 +1。

性質(zhì)4:具有n個結(jié)點的完全二叉樹的深度為log2(n)向下取整+1 證明:設(shè)完全二叉樹的深度為k,需證明: k=floor(log2(n))+1

根據(jù)完全二叉樹的定義可知:前k ? 1層一定是滿的。
根據(jù)二叉樹的性質(zhì)2可知:前k ? 1 層結(jié)點數(shù)為2 ^ (k-1)-1
2 ^ (k-1)-1對上面的獅子兩邊取對數(shù):k-1<=log2(n)得出k是整數(shù),所以k=floor(log2(n))+1成功證明

性質(zhì)5:編號為k的節(jié)點的左節(jié)點等于2k,右節(jié)點等于2k+1 額…沒啥好證的了 三、二叉樹的存儲 1.數(shù)組存儲

我們可以通過二叉樹的編號進行存儲,tr[i]表示編號為i的節(jié)點的信息。
我們可以通過剛才的性質(zhì)5,可以快速的得出編號為k的節(jié)點:

雙親(父節(jié)點)等于floor(k/2)
左節(jié)點等于2k
右節(jié)點等于2k+1

int trv[N];
void UpdateLeft(int p,int v)trv[p<<1]=v;//p<<1等效p*2
void UpdateRight(int p,int v)trv[p<<1|1]=v;//p<<1|1等效p*2+1,注意:s|1不一定等于s+1

并且在完全二叉樹的時候非常節(jié)省空間。
但是在非完全二叉樹的時候會比較浪費空間,所以我們就要引出新的存儲方法——鏈表

2.鏈表存儲

由于二叉樹每個節(jié)點最多有兩個孩子,所以我們可以為其設(shè)計一個鏈表來存儲二叉樹,這個鏈表叫二叉鏈表。

struct Edge{int dat;
	int LeftChild,RightChild;
}trv[N];
四、二叉樹的遍歷 先序遍歷

先序遍歷的規(guī)則是先根后左右

struct Edge{int dat;
	int LeftChild,RightChild;
}trv[N];
void Prnt(int idx){cout<if(!r)return;
	Prnt(r);                  //根
	PreODR(trv[r].LeftChild); //左
	PreODR(trv[r].RightChild);//右
}
中序遍歷

中序遍歷的規(guī)則是先左后根右

struct Edge{int dat;
	int LeftChild,RightChild;
}trv[N];
void Prnt(int idx){cout<if(!r)return;
	PreODR(trv[r].LeftChild);//左
	Prnt(r);                 //根
	PreODR(trv[r].RightChild);//右
}
后序遍歷

后序遍歷的規(guī)則是先左后右根

struct Edge{int dat;
	int LeftChild,RightChild;
}trv[N];
void Prnt(int idx){cout<if(!r)return;
	PreODR(trv[r].LeftChild);//左
	PreODR(trv[r].RightChild);//右
	Prnt(r);                 //根
}
層次遍歷

層次遍歷就和圖的bfs一樣,就是按照層次和每一個層次里的順序來遍歷

struct Edge{int dat;
	int LeftChild,RightChild;
}trv[N];
void Prnt(int idx){cout<queueq;q.push(r);
	Prnt(r);
	while(!q.empty()){int t=q.front();q.pop();
		if(trv[t].LeftChild){	Prnt(trv[t].LeftChild);
			q.push(trv[t].LeftChild);
		}
		if(trv[t].RightChild){	Prnt(trv[t].RightChild);
			q.push(trv[t].RightChild);
		}
	}
}
五、求解先序、后序、層次遍歷序列 1.中序后續(xù)求先序

方法1:
① 找根:基于后序序列的尾元素即是根,找出樹的根。
② 劃分子問題:基于中序序列、根和后序序列,劃分出左右子樹的中序和后序序列。
③ 治理子問題:基于左右子樹的中序和后序序列,遞歸的處理左右子樹。
④ 合并:將左右子樹根節(jié)點的存儲位置,合并為原樹的左右子樹。
⑤ 先序遍歷:基于構(gòu)建出的樹,進行先序遍歷,輸出先序序列。

struct Node{char dat;
	int l,r;
}tr[N];
int tot;
string in,ps;
int build(int ib,int ie,int pb,int pe){int r=++tot;tr[r].dat=ps[pe];
	int rps=in.find(tr[r].dat);
	interestinglen=rps-ib;
	if(rps>ib)tr[r].l=build(ib,rps-1,pb,pb+len-1);
	if(rpsif(!r)return;
	cout<cin>>in>>ps;
	int r=build(0,in.size()-1,0,ps.size()-1);
	ODR(r);
}

方法2:
在算法1的處理過程中直接輸出根,接著先遞歸處理左子樹,再遞歸處理右子樹。

string in,ps;
void solve(int ib,int ie,int pb,int pe){char r=ps[pe];
	cout<ib)solve(ib,rps-1,pb,pb+len-1);
	if(rps
2.前序中序求后序

方法1:
① 找根:基于先序序列的首元素即是根,找出樹的根。
② 劃分子問題:基于中序序列、根和先序序列,劃分出左右子樹的中序和先序序列。
③ 治理子問題:基于左右子樹的中序和先序序列,遞歸的處理左右子樹。
④ 合并:將左右子樹根節(jié)點的存儲位置,合并為原樹的左右子樹。
⑤ 后序遍歷:基于構(gòu)建出的樹,進行后序遍歷,輸出后序序列。

struct Node{char dat;
	int l,r;
}tr[N];
int tot;
string in,pr;
int build(int ib,int ie,int pb,int pe){int r=++tot;
	tr[r].dat=pr[pb];
	int rps=in.find(tr[r].dat);
	int len=rps-ib;
	if(rps>ib)tr[r].l=build(ib,rps-1,pb+1,pb+len);
	if(rpsif(!r)return;
	ODR(tr[r].l);
	ODR(tr[r].r);
	cout<cin>>in>>pr;
	int r=build(0,in.size()-1,0,pr.size()-1);
	ODR(r);
}

方法2:
在算法1處理過程中,找到根后先儲存,當遞歸處理完左右子樹后,再輸出根。

string in,pr;
void solve(int ib,int ie,int pb,int pe){char r=pr[pb];
	int rps=in.find(r);
	int len=rps-ib;
	if(rps>ib)solve(ib,rps-1,pb+1,rp+len);
	if(rpscin>>in>>pr;
	solve(0,in.size()-1,0,pr.size()-1);
}
3.前序中序求層次

① 找根:基于先序序列的首元素即是根,找出樹的根。
② 劃分子問題:基于中序序列、根和先序序列,劃分出左右子樹的中序和先序序列。
③ 治理子問題:基于左右子樹的中序和先序序列,遞歸的處理左右子樹。
④ 合并:將左右子樹根節(jié)點的存儲位置,合并為原樹的左右子樹。
⑤ 層次遍歷:基于構(gòu)建出的樹,進行層次遍歷,輸出層次序列。

struct Node{char dat;
	int l,r;
}tr[N];
int tot;
string in,pr;
int build(int ib,int ie,int pb,int pe){int r=++tot;
	tr[r].dat=pr[pb];
	int rps=in.find(tr[r].dat);
	int len=rps-ib;
	if(rps>ib)tr[r].l=build(ib,rps-1,pb+1,pb+len);
	if(rpscout<queueq;q.push(r);
	Prnt(r);
	while(!q.empty()){int n=q.ront();q.pop();
		if(tr[n].l){	Prnt(tr[n].l);
			q.push(tr[n].l);
		}
		if(tr[n].r){	Prnt(tr[n].r);
			q.push(tr[n].r);
		}
	}
}
int main(){cin>>in>>pr;
	int r=build(0,in.size()-1,0,pr.size()-1);
	bfs(r);
}
4.中序?qū)哟吻笙刃?p>① 找根:基于層次遍歷的首元素是整棵樹的根,找出樹根。
② 劃分子問題:基于中序序列和根可以劃分出左右子樹的中序序列。

通過中序序列可以得到左子樹和右子樹各自所包含的所有節(jié)點,左子樹的所有節(jié)點中最先
出現(xiàn)在層次遍歷序列中的節(jié)點是左子樹的根,同理可得右子樹的根。

string in,l;
int fr(int ib,int ie){for(int i=0;iint r=fr(ib,ie);cout<ib)solve(ib,r-1);
	if(rcin>>in>>l;solve(0,in.size()-1);
}
六、例題 1.小球下落-簡化版
有一棵二叉樹,大深度為D,且所有葉子的深度都相同。所有節(jié)點從上到下,從左到右的編號為1,2,3...,2^D-1.

在結(jié)點1處放一個小球,它會往下落,每個內(nèi)結(jié)點上都有一個開關(guān)(開關(guān)的狀態(tài)是false或true),初始時全部是false狀態(tài),當每次有小球落到這個結(jié)點上時,開關(guān)的狀態(tài)被改變。

當小球達到一個內(nèi)結(jié)點時,如果該結(jié)點的開關(guān)狀態(tài)是關(guān)閉的,則小球往左走,否則往右走,直到走到葉子結(jié)點。

如下圖所示:



表示結(jié)點編號為1,2,3...15,大深度為4的完全二叉樹,由于初始時,所有的結(jié)點的開關(guān)狀態(tài)是false,所以第一個球下落時經(jīng)過結(jié)點1 2 4最終落在結(jié)點8上,第二個球下落時經(jīng)過結(jié)點1 3 6最終落在結(jié)點12上,第三個球下落時,經(jīng)過結(jié)點1 2 5最終落在結(jié)點10上。

現(xiàn)在給出多組測試數(shù)據(jù),最多包含1000組,每組測試數(shù)據(jù)兩個值。第一個值是D,表示二叉樹的大深度。第二個值是L,表示小球的個數(shù)L。

假設(shè)I不超過整棵樹的葉子個數(shù),2≤D≤20,and 1≤L≤5000

編寫一個程序,計算出小球從節(jié)點1處依次開始下落,最后一個小球L將會落下哪里?輸出第L個小球最后所在的葉子編號。

輸入格式
第一行一個整數(shù)n,表示測試數(shù)據(jù)的組數(shù)

接下來n行,每行兩個整數(shù)分別表示二叉樹的深度D和小球的個數(shù)L,用空格隔開

最后一行,“-1”,表示測試數(shù)據(jù)結(jié)束

輸出格式
輸出n行,分別表示每組測試數(shù)據(jù),第L個小球最后所在的葉子編號

輸入輸出樣列
輸入樣例1:
5
4 2
3 4
10 1
2 2
8 128
-1
輸出樣例1:
12
7
512
3
255

這道題就是個大大大大大氵題,直接按照題目的思路模擬即可。

#include#define debug(x) cout<< #x<< '='<< x<< '\n';
using namespace std;
bool tr[1000010]; //lson=t*2,rson=t*2+1
int T;
void slove(){memset(tr,0,sizeof(tr));
	int D,L;scanf("%d%d",&D,&L);
	int a=(1<int now=1;
		while(now	int t=now;
			if(!tr[now])now=now<<1;
			else now=now<<1|1;
			tr[t]^=1;
		}x=now;
	}
	printf("%d\n",x);
}
int main () {scanf("%d",&T);
	while(T--)slove();
	return 0;
}
2.美國血統(tǒng) American Heritage [USACO 3.4]
農(nóng)夫約翰非常認真地對待他的奶牛們的血統(tǒng).然而他不是一個真正優(yōu)秀的記帳員.他把他的奶牛們的家譜作成二叉樹,并且把二叉樹以更線性的”樹的中序遍歷“和”樹的前序遍歷“的符號加以記錄而不是用圖形的方法.

你的任務(wù)是在被給予奶牛家譜的”樹中序遍歷“和”樹前序遍歷“的符號后,創(chuàng)建奶牛家譜的”樹的后序遍歷“的符號。每一頭奶牛的姓名被譯為一個唯一的字母. (你可能已經(jīng)知道你可以在知道樹的兩種遍歷以后可以經(jīng)常地重建這棵樹.)顯然,這里的樹不會有多余 26 個的頂點.

這是在樣例輸入和 樣例輸出中的樹的圖形表達方式:

                 C
                /   \
               /     \
              B       G
             / \     /
            A   D   H
               / \
              E   F
樹的中序遍歷是按照左子樹,根,右子樹的順序訪問節(jié)點。

樹的前序遍歷是按照根,左子樹,右子樹的順序訪問節(jié)點。

樹的后序遍歷是按照左子樹,右子樹,根的順序訪問節(jié)點。

輸入格式
第一行: 樹的中序遍歷

第二行: 同樣的樹的前序遍歷

輸出格式
單獨的一行表示該樹的后序遍歷.

輸入輸出樣列
輸入樣例1:
ABEDFCHG
CBADEFGH
輸出樣例1:
AEFDBHGC

模板題啊。

#include#define debug(x) cout<< #x<< '='<< x<< '\n';
using namespace std;
string p, i;
void build (string p, string i) {if (p.empty ()) return;
    char r = p[0];
    int k = i.find (r);
    p.erase (p.begin ());
    string l1 = p.substr (0, k);
    string r1 = p.substr (k);
    string l2 = i.substr (0, k);
    string r2 = i.substr (k + 1);
    build (l1, l2);
    build (r1, r2);
    cout<< r;
}
int main () {cin >>i >>p;
    build (p, i);
	return 0;
}
二叉堆 一、二叉堆簡介

二叉堆使用完全二叉樹實現(xiàn),分為大根堆和小根堆兩種:
大根堆:任意一個分支結(jié)點的值都大于或者等于其子節(jié)點的值。
小根堆:任意一個分支結(jié)點的值都小于或者等于其子節(jié)點的值。

查詢大值(大根堆)和最小值(小根堆)時,直接取根節(jié)點即可,時間復(fù)雜度O(1) 二、二叉堆的插入操作

插入操作要求在不影響二叉堆性質(zhì)的前提下,在二叉堆中添加一個新元素。
性質(zhì)1:完全二叉樹結(jié)構(gòu),插入新元素后需要繼續(xù)保持完全二叉樹的結(jié)構(gòu)。
性質(zhì)2:任何一個分支節(jié)點的值都大于等于(大根堆)或小于等于(小根堆)其子節(jié)點的值。

① 堆尾插入:每次在堆尾插入新元素(確保插入后仍然是完全二叉樹結(jié)構(gòu))。
② 向上調(diào)整(和父節(jié)點比較),將新元素調(diào)整到合適的位置。

三、二叉堆的刪除堆頂操作

刪頂操作要求在不影響二叉堆性質(zhì)的前提下,將堆頂元素刪除。
性質(zhì)1:完全二叉樹結(jié)構(gòu),刪除堆頂后需要繼續(xù)保持完全二叉樹的結(jié)構(gòu)。
性質(zhì)2:任何一個分支節(jié)點的值都大于等于(大根堆)或小于等于(小根堆)其子節(jié)點的值。

① 將堆頂賦值為堆尾元素的值,接著刪除堆尾節(jié)點。(保持完全二叉樹結(jié)構(gòu))
② 向下調(diào)整(和孩子節(jié)點比較),堆頂元素調(diào)整到合適的位置。

我們可以通過數(shù)組來實現(xiàn)這個二叉堆! 四、二叉堆復(fù)雜度分析

插入操作:堆尾添加元素時間復(fù)雜度O(1),向上調(diào)整的次數(shù)大為完全二叉樹的層數(shù):
log2 n + 1,故插入操作的時間復(fù)雜度為:O(log2 n )。
刪頂操作:堆頂復(fù)制和堆尾刪除時間復(fù)雜度O(1), 向下調(diào)整的次數(shù)大為完全二叉樹
的層數(shù): log2 n + 1,故刪頂操作的時間復(fù)雜度為:O(log2 n )。

五、二叉堆代碼實現(xiàn)
int heap[N],tt;
bool empty(){return !tt;}
int sz(){return tt;}
int tp(){return heap[1];}
int psh(int v){heap[++tt]=v;
	int x=tt;
	while(x>1&&heap[x]>1]){swap(heap[x>>1],heap[x]);
		x>>=1;
	}
}
void pop(){heap[1]=heap[tt--];
	int x=1,p=x<<1;
	while(p<=tt){if(p+1<=tt&&heap[p+1]
六、優(yōu)先隊列

優(yōu)先隊列priority_queue和堆是實現(xiàn)的相近的功能:插入一個數(shù)和刪除最小或大的值
常用函數(shù):
在這里插入圖片描述
優(yōu)先隊列也是可以使用小根堆和大根堆的,分別是greater(上升)、less(下降)
就比如:

priority_queue,greater>qg;
priority_queue,less>ql;

然后就比如插入一個數(shù)x:

q.push(x);

刪除隊頭(同前面的堆頂):

q.pop();

同樣,優(yōu)先隊列的類型也可以是結(jié)構(gòu)體,但是需要重載運算符。
大根堆需要重載小于運算符

struct Node{int a;
	bool operator<(const Node&W)const{return a>W.a;
	}
}
priority_queue,less>q;

小根堆需要重載大于運算符

struct Node{int a;
	bool operator<(const Node&W)const{return a,greater>q;
七、例題
有兩個長度都是N的序列A和B,在A和B中各取一個數(shù)相加可以得到N^2個和,求這N^2個和中最小的N個。

輸入格式
第一行一個正整數(shù)N;

第二行N個整數(shù)Ai,滿足Ai<=Ai+1且Ai<=10^9;(i和i+1表示序列的下標)

第三行N個整數(shù)Bi, 滿足Bi<=Bi+1且Bi<=10^9。(i和i+1表示序列的下標)

輸出格式
輸出僅一行,包含N個整數(shù),從小到大輸出這N個最小的和,相鄰數(shù)字之間用空格隔開。

輸入輸出樣列
輸入樣例1:
3
2 6 6
1 4 8
輸出樣例1:
3 6 7
說明
【數(shù)據(jù)規(guī)模】

對于50%的數(shù)據(jù)中,滿足1<=N<=1000;

對于100%的數(shù)據(jù)中,滿足1<=N<=100000。

在這里插入圖片描述
同樣的反過來統(tǒng)計也一樣:

#includeusing namespace std;
typedef pairPII; 
const int N=1e5+10;
int n,a[N],b[N],t[N];
priority_queue,greater>q;
int main(){cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)cin>>b[i];
	for(int i=1;i<=n;i++)q.push(make_pair(a[1]+b[i],i)),t[i]=1;
	for(int i=1;i<=n;i++){cout<

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

本文題目:【c++提高1】二叉樹&二叉堆(萬字總結(jié))-創(chuàng)新互聯(lián)
轉(zhuǎn)載注明:http://muchs.cn/article30/pshso.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、定制網(wǎng)站、網(wǎng)站建設(shè)、做網(wǎng)站、搜索引擎優(yōu)化、云服務(wù)器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)