線性表演算法設計題1

聽說呢稱一個月只能修改一次 發表於 2020-10-17

1.設線性表L=(a1,a2,a3,…,a[n-2],a[n-1],an)採用帶頭結點的單連結串列儲存,連結串列中結點定義如下:
typedef struct node{
int data;
struct node* next;
}NODE;
請設計一個空間複雜度為O(1)且時間上儘可能高效的演算法,重新排列L中的個結點得到線性表L’=(a1,an,a2,a[n-1],a3,a[n-2],…)。
要求:
(1)給出演算法的基本設計思想。
(2)根據設計思想,採用c或c++語言描述演算法,關鍵之處給出註釋。
(3)說明你所設計的演算法的時間複雜度。【2019年全國試題41(13)分】

答:(1)將原有連結串列從中間分為兩部分,分別是(a1,a2,a3,…a[n/2])和(a[n/2+1],a[n/2+2],…,a[n])。將後一部分連結串列逆置,再將兩個連結串列合併。
(2)核心語句

int i=1;
p=head->next;	//設head是指向帶頭結點的單連結串列的指標
while(i<n/2){	//n為元素個數(題目有提示)
	p=p->next;//找到兩個連結串列的分界點,即中間結點
	i++;
}
r=p->next;     //r即為第二個連結串列的頭結點
p->next=null;//p結點是前一半的尾結點
q=null;	     //為逆置做準備,q指向逆置表的首元結點
while(r){//連結串列逆置
	p=r->next;//暫存後繼
	r->next=q;//就地逆置
	q=r;		//r(或q)指向連結串列新首元
	r=p;		//指向待逆置結點
}
p=head->next;//head是指向帶頭結點的單連結串列的指標,p指向連結串列的第一個元素
while(p->next&&q->next){	
	p->next=r;	//暫存兩連結串列後繼
	q->next=s;	
	p->next=q->next;	//合併連結串列,將q結點插入到對應p結點的後面
	p=r;				//恢復指向待合併結點
	q=s;			
}
if(p->next==null)	//*避免n為奇數,這步有些小問題,稍後修改*
	p->next=q;
else
	q->next=p;

(3)演算法的時間複雜度為O(n)。

總結
1.演算法涉及
(1)拆分連結串列
(2)逆置連結串列
(3)合併連結串列

逆置連結串列的幾種擴充:
1.無頭結點的單連結串列的逆置
2.帶附加頭結點的單連結串列的逆置

eg1:有一個無頭結點的單連結串列,結點有資料域data、指標域next,表頭指標為h,通過遍歷連結串列,將連結串列中所有的連結方向逆轉。要求逆轉後的連結串列的表頭指標h指向原連結串列的最後一個結點。演算法如下所示。【南京理工大學2005二、1(3分)】

void Inverse(&h){
	if(h==null)
	return ;
	p=h->next;
	pr=null;
	while(p){
	h->next=pr;
	pr=h;
	h=p;
	p=p->next;
	}
	head->next=pr;
}

eg2:以下程式的功能就是實現帶附加頭結點的單連結串列資料結構逆序連結【西南交通大學2000一、9】

void reverse(pointer h){
/*h為附加頭結點*/
	pointer p,q;
	p=h->next;
	h->next=null;
	while(p!=null){
	q=p;
	p=p->next;
	q->next=h->next;
	h->next=q;
	}
}