PTA鏈表習題集合[11-2-1~11-2-9]

PTA鏈表習題集合[11-2-1~11-2-9]

1.實驗11-2-1 建立學生信息鏈表 (20分)

本題要求實現一個將輸入的學生成績組織成單向鏈表的簡單函數。

函數接口定義:(尾插法)

void input();    

該函數利用scanf從輸入中獲取學生的信息,並將其組織成單向鏈表。鏈表節點結構定義如下:

struct stud_node {
    int              num;      /*學號*/
    char             name[20]; /*姓名*/
    int              score;    /*成績*/
    struct stud_node *next;    /*指向下個結點的指針*/
};      

單向鏈表的頭尾指針保存在全局變量headtail中。

輸入爲若干個學生的信息(學號、姓名、成績),當輸入學號爲0時結束。

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct stud_node {
     int    num;
     char   name[20];
     int    score;
     struct stud_node *next;
};
struct stud_node *head, *tail;

void input();

int main()
{
    struct stud_node *p;
	
    head = tail = NULL;
    input();
    for ( p = head; p != NULL; p = p->next )
        printf("%d %s %d\n", p->num, p->name, p->score);

    return 0;
}

/* 你的代碼將被嵌在這裏 */

      
    

輸入樣例:

1 zhang 78
2 wang 80
3 li 75
4 zhao 85
0    

輸出樣例:

1 zhang 78
2 wang 80
3 li 75
4 zhao 85

函數代碼:

void input()
{
	//已存在head,tail;
	int    num;
    char   name[20];
    int    score;
	struct stud_node *p;
	//輸入學號姓名班級 
	scanf("%d",&num);
	//學號不爲0時循環 
	while(num!=0)
	{
		scanf("%s%d",name,&score);
		//申請新結點 
		p = (struct stud_node*)malloc(sizeof(struct stud_node));
		p->next=NULL; //新結點的下一個結點指空 
		//賦值新結點 
		p->num=num;
		strcpy(p->name,name);
		p->score=score;
		//判斷是否爲首結點,是則直接賦值,不是則尾接 
		if(tail==NULL)
			head=p;
		else
		{
			tail->next=p;	
		}
		tail=p;	//尾指針移動 
		scanf("%d",&num);
	} 
} 

2.實驗11-2-2學生成績鏈表處理(20分)

本題要求實現兩個函數,一個將輸入的學生成績組織成單向鏈表;另一個將成績低於某分數線的學生結點從鏈表中刪除。

函數接口定義:

struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );   

函數createlist利用scanf從輸入中獲取學生的信息,將其組織成單向鏈表,並返回鏈表頭指針。鏈表節點結構定義如下:

struct stud_node {
    int              num;      /*學號*/
    char             name[20]; /*姓名*/
    int              score;    /*成績*/
    struct stud_node *next;    /*指向下個結點的指針*/
};   

輸入爲若干個學生的信息(學號、姓名、成績),當輸入學號爲0時結束。

函數deletelist從以head爲頭指針的鏈表中刪除成績低於min_score的學生,並返回結果鏈表的頭指針。

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>

struct stud_node {
     int    num;
     char   name[20];
     int    score;
     struct stud_node *next;
};

struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );

int main()
{
    int min_score;
    struct stud_node *p, *head = NULL;

    head = createlist();
    scanf("%d", &min_score);
    head = deletelist(head, min_score);
    for ( p = head; p != NULL; p = p->next )
        printf("%d %s %d\n", p->num, p->name, p->score);

    return 0;
}

/* 你的代碼將被嵌在這裏 */

      
    

輸入樣例:

1 zhang 78
2 wang 80
3 li 75
4 zhao 85
0
80    

輸出樣例:

2 wang 80
4 zhao 85

函數代碼:

struct stud_node *createlist()
{
	//已存在head,tail;
	int    num;
	char   name[20];
    int    score;
	struct stud_node *p,*head=NULL,*tail;
	tail=head;
	//輸入學號 
	scanf("%d",&num);
	//學號不爲0時循環 
	while(num!=0)
	{
		//申請新結點 
		p = (struct stud_node*)malloc(sizeof(struct stud_node));
		//賦值新結點
		scanf("%s %d",p->name,&p->score);
		p->num=num;
		p->next=NULL; //新結點的下一個結點指空 
		//判斷是否爲首結點,是則直接賦值,不是則尾接 
		if(tail==NULL)
			head=p;
		else
		{
			tail->next=p;	
		}
		tail=p;	//尾指針移動 
		scanf("%d",&num);
	} 
	
	return head;
} 

struct stud_node *deletelist( struct stud_node *head, int min_score )
{
	//刪除成績低於min_score的學生,返回頭指針 
	struct stud_node *move,*front;
	move=head;
	front=NULL; 
	while(move)
	{
		//若符合小於min_score 
		if(move->score<min_score)
		{
			//若爲第一個,則移動頭指針後移一位 
			if(front==NULL)
				head=head->next;
			//若非第一位則,move的前一個節點指向move的後一個節點,跳過move 
			else
				front->next=move->next;
	
		}//不符合則front移動到當前move的位置  保留前一個結點做標記 
		else
			front=move;
		//move向下一個結點移動			
		move=move->next;
	} 
	
	return head;	
}


3.實驗11-2-3逆序數據建立鏈表 (20分)

本題要求實現一個函數,按輸入數據的逆序建立一個鏈表。

函數接口定義:(頭插法)

struct ListNode *createlist();    

函數createlist利用scanf從輸入中獲取一系列正整數,當讀到−1時表示輸入結束。按輸入數據的逆序建立一個鏈表,並返回鏈表頭指針。鏈表節點結構定義如下:

struct ListNode {
    int data;
    struct ListNode *next;
};    

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *createlist();

int main()
{
    struct ListNode *p, *head = NULL;

    head = createlist();
    for ( p = head; p != NULL; p = p->next )
        printf("%d ", p->data);
    printf("\n");

    return 0;
}

/* 你的代碼將被嵌在這裏 */

    

輸入樣例:

1 2 3 4 5 6 7 -1    

輸出樣例:

7 6 5 4 3 2 1 

函數代碼:

struct ListNode *createlist()
{
	int data;
	struct ListNode *head = (struct ListNode*)malloc(sizeof(struct ListNode)); //創建一個空的頭結點 
	struct ListNode *insert;
	head->next=NULL; //頭指針指空 
	insert=head; //建立一個指針指向頭結點 
	scanf("%d",&data);
	while(data!=-1)
	{
		struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode)); //申請新結點 
		p->data=data; 
		//頭插法核心 
		p->next=insert->next; //新節點指向頭指針的下一個節點 
		insert->next=p;	//頭指針指向新節點 
		scanf("%d",&data);
	}
		
	return head->next;	//返回的不是頭指針而是首個結點,既頭指針指向的下一個結點 
} 


4.實驗11-2-4 刪除單鏈表偶數節點(20分)

本題要求實現兩個函數,分別將讀入的數據存儲爲單鏈表、將鏈表中偶數值的結點刪除。鏈表結點定義如下:

struct ListNode {
    int data;
    struct ListNode *next;
};   

函數接口定義:

struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );   
    

函數createlist從標準輸入讀入一系列正整數,按照讀入順序建立單鏈表。當讀到−1時表示輸入結束,函數應返回指向單鏈表頭結點的指針。

函數deleteeven將單鏈表head中偶數值的結點刪除,返回結果鏈表的頭指針。

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );
void printlist( struct ListNode *head )
{
     struct ListNode *p = head;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode *head;

    head = createlist();
    head = deleteeven(head);
    printlist(head);

    return 0;
}

/* 你的代碼將被嵌在這裏 */

        

輸入樣例:

1 2 2 3 4 5 6 7 -1   

輸出樣例:

1 3 5 7 

函數代碼:

/* 你的代碼將被嵌在這裏 */
struct ListNode *createlist()
{
	struct ListNode *head=NULL,*p,*last;
    int n;
	last=head; //last指針用於移動表示鏈表末尾 
	do{
		scanf("%d",&n); //輸入結點數值 
		if(n!=-1)
		{
			p=(struct ListNode *)malloc(sizeof(struct ListNode));  //申請新節點 
			p->data=n; //新節點賦值 
			p->next=NULL; //新節點指空 
			if(last==NULL) //若爲頭結點時 
				head=p;
			else
				last->next=p; //非頭結點時,尾接 
			last=p;	//標誌位移動到新節點處		
		}
		else
			break;	
	}while(n!=-1);
	
	return head;				
}

struct ListNode *deleteeven( struct ListNode *head )
{
	//刪除偶數結點 
	struct ListNode *move,*front;
	move=head;
	front=NULL; 
	while(move)
	{
		//若符合data爲偶數 
		if((move->data)%2==0)
		{
			//若爲第一個,則移動頭指針後移一位 
			if(front==NULL)
				head=head->next;
			//若非第一位則,move的前一個節點指向move的後一個節點,跳過move 
			else
				front->next=move->next;
	
		}//不符合則front移動到當前move的位置  保留前一個結點做標記 
		else
			front=move;
		//move向下一個結點移動			
		move=move->next;
	} 
	
	return head;	
} 

5.實驗11-2-5鏈表拼接(20分)

本題要求實現一個合併兩個有序鏈表的簡單函數。鏈表結點定義如下:

struct ListNode {
    int data;
    struct ListNode *next;
};    

函數接口定義:

struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2);   

其中list1list2是用戶傳入的兩個按data升序鏈接的鏈表的頭指針;函數mergelists將兩個鏈表合併成一個按data升序鏈接的鏈表,並返回結果鏈表的頭指針。

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *createlist(); /*裁判實現,細節不表*/
struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2);
void printlist( struct ListNode *head )
{
     struct ListNode *p = head;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode  *list1, *list2;

    list1 = createlist();
    list2 = createlist();
    list1 = mergelists(list1, list2);
    printlist(list1);
	
    return 0;
}

/* 你的代碼將被嵌在這裏 */

       

輸入樣例:

1 3 5 7 -1
2 4 6 -1    

輸出樣例:

1 2 3 4 5 6 7 

函數代碼:

/* 你的代碼將被嵌在這裏 */
struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2)
{
	//函數mergelists將兩個鏈表合併成一個按data升序鏈接的鏈表 --合併---升序 
	//思路1.是相當於刪除後一個鏈表的結點,在插入到前一個鏈表裏。 
	//思路2,先合併兩個鏈表,在利用指針變量做若干次冒泡排序。
	
	if(list1==NULL&&list2)
		return list2;
	if(list2==NULL&&list1)
		return list1;
	if(list1==NULL&&list2==NULL)
		return NULL;
	struct ListNode *move1,*move2,*save,*front; //move1.2 分別用於移動,save用來指向從list2取下結點的地址 
	move2=list2;
	move1=list1;
	while(move2)
	{
		//<---取結點--->
		save=move2; //保存list2當前節點 
		move2=move2->next; //list2首結點後移 
		save->next=NULL; //當前節點指空 ,取下結點 
		
		//<---插入結點到符合條件位置--->
		//重置move1首結點地址,front指針 
		move1=list1;
		front=NULL; 
		while(move1)
		{	 
			if(save->data<move1->data)
			{
				if(front)
				{
					//頭插法核心 ,當data的值在list1中間時
					save->next=front->next;
					front->next=save;
					break; 
				}else{
					//當data的值比list1所有值都小的時候 
					save->next=list1;
					list1=save;
					break;
				}	
			}else
				front=move1;	
			move1=move1->next;
		}
					
		//尾插法 當data的值比list1所有值都大的時候 	
		if(move1==NULL)
		{
			front->next=save;	
		}	
		
	} 
	
	//返回list1首地址 
	return list1;	
} 
  

6.實驗11-2-6 奇數值結點鏈表 (20分)

本題要求實現兩個函數,分別將讀入的數據存儲爲單鏈表、將鏈表中奇數值的結點重新組成一個新的鏈表。鏈表結點定義如下:

struct ListNode {
    int data;
    ListNode *next;
};    

函數接口定義:

struct ListNode *readlist();
struct ListNode *getodd( struct ListNode **L );
   

函數readlist從標準輸入讀入一系列正整數,按照讀入順序建立單鏈表。當讀到−1時表示輸入結束,函數應返回指向單鏈表頭結點的指針。

函數getodd將單鏈表L中奇數值的結點分離出來,重新組成一個新的鏈表。返回指向新鏈表頭結點的指針,同時將L中存儲的地址改爲刪除了奇數值結點後的鏈表的頭結點地址(所以要傳入L的指針)。

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *readlist();
struct ListNode *getodd( struct ListNode **L );
void printlist( struct ListNode *L )
{
     struct ListNode *p = L;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode *L, *Odd;
    L = readlist();
    Odd = getodd(&L);
    printlist(Odd);
    printlist(L);

    return 0;
}

/* 你的代碼將被嵌在這裏 */

      
    

輸入樣例:

1 2 2 3 4 5 6 7 -1   

輸出樣例:

1 3 5 7 
2 2 4 6 

函數代碼:

/* 你的代碼將被嵌在這裏 */
struct ListNode *readlist()
{
	struct ListNode *head=NULL,*p,*last;
    int n;
	last=head; //last指針用於移動表示鏈表末尾 
	do{
		scanf("%d",&n); //輸入結點數值 
		if(n!=-1)
		{
			p=(struct ListNode *)malloc(sizeof(struct ListNode));  //申請新節點 
			p->data=n; //新節點賦值 
			p->next=NULL; //新節點指空 
			if(last==NULL) //若爲頭結點時 
				head=p;
			else
				last->next=p; //非頭結點時,尾接 
			last=p;	//標誌位移動到新節點處		
		}
		else
			break;	
	}while(n!=-1);
	
	return head;				
}

struct ListNode *getodd( struct ListNode **L )
{
	//奇數分離構成新鏈表,返回刪除奇數的鏈表的頭結點 
	struct ListNode *odd=NULL,*last,*p,*q,*k;
	last=odd;  //用於奇數鏈表鏈表 插入新節點
	p=*L;    //表示原鏈表移動指針 
	q=NULL; //q初始化,作爲原鏈表移動指針前一個節點的標記 
	while(p)
	{
		if((p->data)%2) //data取餘2爲 1 則爲奇數,刪除節點 
		{
			if(q&&p!=*L) //非L收個節點就是奇數的情況 
			{
				k=p; //保存奇數節點 
				q->next=p->next; //刪除奇數節點 
				
				if(last!=NULL)    //插入odd鏈表 
					last->next=k;
				else
					odd=k;
				last=k;		
			}	
			else //L的第一個就是奇數的情況  
			{ 
				k=p;              //保存奇數節點 
				*L=p->next;       //頭結點向後移動,刪除奇數節點 
				
				if(last!=NULL)    //插入odd鏈表 
					last->next=k;
				else
					odd=k;
				last=k;		
			}
		}
		else
			q=p; //未找到奇數節點,則用q保留當前位置 		 
		p=p->next; //p指針繼續向下移動
        if(last) //odd鏈表非空則
		    last->next=NULL;  //odd末尾指針指空 
	} 
	return odd;		
}

7.實驗11-2-7 統計專業人數 (15分)

本題要求實現一個函數,統計學生學號鏈表中專業爲計算機的學生人數。鏈表結點定義如下:

struct ListNode {
    char code[8];
    struct ListNode *next;
};    

這裏學生的學號共7位數字,其中第2、3位是專業編號。計算機專業的編號爲02。

函數接口定義:

int countcs( struct ListNode *head );   

其中head是用戶傳入的學生學號鏈表的頭指針;函數countcs統計並返回head鏈表中專業爲計算機的學生人數。

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct ListNode {
    char code[8];
    struct ListNode *next;
};

struct ListNode *createlist(); /*裁判實現,細節不表*/
int countcs( struct ListNode *head );

int main()
{
    struct ListNode  *head;

    head = createlist();
    printf("%d\n", countcs(head));
	
    return 0;
}

/* 你的代碼將被嵌在這裏 */

      
    

輸入樣例:

1021202
2022310
8102134
1030912
3110203
4021205
#    

輸出樣例:

3

函數代碼:

int countcs( struct ListNode *head )
{
	//統計並返回head鏈表中專業爲計算機的學生人數
	int i,count=0,item;
	struct ListNode *p=head;
    //p指針用來遍歷鏈表
	while(p)
	{
		//只讀取code數組下標爲1.2的字符
        for(item=0,i=1;i<=2;i++)
		{
			//字符轉整數
            item=item*10+(p->code[i]-'0');
		}
		//判斷是否爲2
		if(item==2)
		{
			count++;
		}
        //移動指針
		p=p->next;
	}
	//返回計數
	return count;
}

8.實驗11-2-8 單鏈表結點刪除 (20分)

本題要求實現兩個函數,分別將讀入的數據存儲爲單鏈表、將鏈表中所有存儲了某給定值的結點刪除。鏈表結點定義如下:

struct ListNode {
    int data;
    ListNode *next;
};

      
    

函數接口定義:

struct ListNode *readlist();
struct ListNode *deletem( struct ListNode *L, int m );

      
    

函數readlist從標準輸入讀入一系列正整數,按照讀入順序建立單鏈表。當讀到−1時表示輸入結束,函數應返回指向單鏈表頭結點的指針。

函數deletem將單鏈表L中所有存儲了m的結點刪除。返回指向結果鏈表頭結點的指針。

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *readlist();
struct ListNode *deletem( struct ListNode *L, int m );
void printlist( struct ListNode *L )
{
     struct ListNode *p = L;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    int m;
    struct ListNode *L = readlist();
    scanf("%d", &m);
    L = deletem(L, m);
    printlist(L);

    return 0;
}

/* 你的代碼將被嵌在這裏 */

      
    

輸入樣例:

10 11 10 12 10 -1
10

      
    

輸出樣例:

11 12 

函數代碼:

struct ListNode *readlist()
{
	//---**尾插法**--- 
	//定義3個指針變量
	//head用於返回鏈表的首結點,先初始化指空
	//p 用於申請新節點 
	//last 用於連接head和新節點的一個尾指針,並且每次都停留在鏈表結尾 
	struct ListNode *head=NULL,*p,*last;
	int n;
	//先把last指向head ,起始時首尾都在一起 
	last=head; 
	
	do{
		//輸入節點信息 
		scanf("%d",&n);
		
		//輸入值!= -1時 操作 
		if(n!=-1)
		{
			//---申請新節點--- 
			p=(struct ListNode *)malloc(sizeof(struct ListNode));
			p->data=n;
			p->next=NULL; //申請的新節點初始化,下一個節點指空 
			
			//---連接節點----
			//head需要返回,不能用來移動,當檢測到尾指針指空,表示首尾指針並未有任何值 
			if(last==NULL)
				head=p; //直接把第一個節點賦值到head   
			else
				last->next=p;  //若last非空 則把p連接到last後一個節點 head->last->p->null; 
			last=p; //連接完後last移動到到p上,既移動到新的結尾 	head->last->p1->last(p)->null;
		}
		else  
			break;
						
	}while(n!=-1);// -1結束循環 
	
	return head;
				
}

struct ListNode *deletem( struct ListNode *L,int m )
{
    //--由於單鏈表遍歷是不可逆的---
	//設置兩個指針一個控制移動,一個用於連接(防止斷鏈)
	 
	struct ListNode *p,*q;
    p=L;  //p用於移動 
    q=NULL;  //q初始化 
    
    //當p非空時 
    while(p)
    {
		//若data爲m 
		if(p->data==m)
    	{
    		//情況1:中間節點或者末尾節點是m ,此時 q!=NULL    
			if(q)
				q->next=p->next;    //q->m(p)->x    q->x			
			//情況2:首節點就是m ,此時 q=NULL 
			else
				L=p->next; //則直接移動鏈表的首結點後移 
		}
		else//data不爲m,則q移動到p當前位置,相當於記錄p前一個節點 
			q=p;
			
		//p指針移動到下一個節點	
    	p=p->next;
	}
	
    return L;
}

9.實驗11-2-9 鏈表逆置 (20分)

本題要求實現一個函數,將給定單向鏈表逆置,即表頭置爲表尾,表尾置爲表頭。鏈表結點定義如下:

struct ListNode {
    int data;
    struct ListNode *next;
};    

函數接口定義:

struct ListNode *reverse( struct ListNode *head );    

其中head是用戶傳入的鏈表的頭指針;函數reverse將鏈表head逆置,並返回結果鏈表的頭指針。

裁判測試程序樣例:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *createlist(); /*裁判實現,細節不表*/
struct ListNode *reverse( struct ListNode *head );
void printlist( struct ListNode *head )
{
     struct ListNode *p = head;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode  *head;

    head = createlist();
    head = reverse(head);
    printlist(head);
	
    return 0;
}

/* 你的代碼將被嵌在這裏 */

      
    

輸入樣例:

1 2 3 4 5 6 -1   

輸出樣例:

6 5 4 3 2 1 

函數代碼:

struct ListNode *reverse( struct ListNode *head )
{
	//時間複雜度爲O(n),空間複雜度爲O(1)
  	//特殊情況,空鏈表
    if(head==NULL)
        return NULL;
     //申請一個空的結點作爲頭結點
    struct ListNode *fake = (struct ListNode*)malloc(sizeof(struct ListNode));	
	struct ListNode *front,*now,*tail;
	fake->next=head;
	front=head; 
    //當now==NULL時,結束循環 	
	do{
		//指針移動 
		now=front->next;
		if(now==NULL)
			break;
		tail=now->next;
		//頭插法 
		front->next=tail;
		now->next=fake->next;
		fake->next=now; 
	}while(1);
	
	return fake->next;
}

圖解:

  • 3個指針變量控制,front,now,tail 前中後
  • 把now取下後頭插到fake後面,循環重複本次操作,當now==NULL時完成逆置。
    在這裏插入圖片描述

完結

總結:(待續)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章