1. 程式人生 > >C語言-------實現一個簡單的單向連結串列

C語言-------實現一個簡單的單向連結串列

編寫一個連結串列程式,在程式中實現簡單的功能
#include <stdio.h>
#include <stdlib.h>

struct node{
   int num;
   char name[20];

   struct node* next;  //指向下一個地址的指標
};  //宣告一個連結串列,此時記憶體不分配記憶體

typedef struct node Node; //重新命名,便於書寫,太長了struct node 
typedef struct node* Link;
//建構函式,實現傳過來的頭指標指向一個空的內容
void creat_node(Link *head) //形參為二級指標,操作的物件是指標變數的指標,這個概念我之前糾結了很久,很容易混.就單純的理解為對變數的值進行操作,這個變數是指標{*head = NULL; //*head是指標的內容}
//頭插,連結串列中節點的插入方式
void insert_head(Link *head,Link p) //函式操作的形參是頭指標和新指標的地址,需要改變頭指標的指向,所以呼叫的是二級指標{Link a;a = *head; if(a == NULL){a = p;p -> next = NULL;}else{p -> next = *head;// *head -> next = NULL;這句被註釋掉了,這個是我當時犯的錯,這樣操作會使連結串列丟失*head = p;}}
//尾插
void insert_tail(Link *head,Link p) //原理同頭插,尾插時注意新節點的next指標要指向NULL,在連結串列中迴圈時注意迴圈結束條件和迴圈體執行的操作
{
	Link a;
	a = *head;

	if( *head == NULL ) //頭指標指向空時,沒有節點
	{
		*head = p;
		p -> next = NULL;
	}
	else
	{
	//	*head -> next = p; 這句犯錯同上,連結串列會斷掉
	    while(a -> next != NULL) //這個迴圈,是在連結串列中找到它的最後一位,把新節點連線上去
		{
			a = a -> next;
		}
	    a -> next = p;
	    p -> next = NULL;
    }

}

//釋放連結串列指標的空間
void release_node(Link head) //釋放空間不需要頭指標的移動,形參呼叫head的一級指標,傳head的指向地址,頭指標的內容改變時,頭指標的指向改變,效果就是頭指標的移動
{
	Link p;  //定義一個指標,指向head,實現對連結串列的操作
	p = head;

	while(p != NULL)
	{
		free(p); //釋放指標變數p指向的空間
		p = p -> next;   // p為變數,更新了p的值,效果是指標變數p現在指向p的下一個節點
	}
}

//列印連結串列中的內容
void display_node(Link head)  //對連結串列的操作,不需要移動head的位置,形參取head的一級指標
{
	Link a; //定義一個新指標變數a,指向head的位置
	a = head;

	while(a != NULL)  //列印節點內容,指標變數a指向下一個節點,實現後移的迴圈,直到a指向一個NULL
	{
		printf("num = %d name = %s\n",a -> num,a -> name);
		a = a -> next;
	}
}

//計算返回一個單向連結串列的長度
int length_node(Link head)  //對連結串列的操作,不需要移動head的位置,形參取head的一級指標
{
	Link p;
	int i = 0; //記錄節點個數
	p = head;

	while(p != NULL)  //直到p指向的空間是NULL
	{
		i++;    //i+1技術
                p = p -> next;  //p指向下一個節點
	}

	return i; //返回值i是int的,要宣告函式的返回值
}

//查詢連結串列中指定節點的內容
void check_node(Link head,int k)  //對連結串列的操作,不需要移動head的位置,形參取head的一級指標,k為指定節點數
{
        Link p;
	p = head;

	if(p == NULL)
		printf("連結串列為空,無內容可查\n");
	else
	{
		while(p != NULL)  //找到連結串列中的指定節點打印出來
		{
			if(p -> num == k)
			{
				printf("name = %s\n",p -> name);
				break; //列印完成後要記得退出迴圈
			}
			else
				p = p -> next; //p指向p的後一位位元組
		} 
	}
}

//刪除指定節點
void delete_node(Link head,int x)  //對連結串列的操作,不需要移動head的位置,形參取head的一級指標,k為指定節點數
{
	Link p,q;
	p = head;

	if(head == NULL)
	{
    	printf("連結串列為空\n");
		return ;
	}

	if(head -> next == NULL)  //連結串列中只有一個節點
	{
	    if(p -> num == x)
          {
			  free(p);
			  p = NULL;
			  return;
		  }
		else
		{
			printf("沒有該節點\n");
			return;
		}
	}

	while(p -> num != x) //找到指定節點刪除
	{
		q = p; //記錄當前p指向的位置,p滿足迴圈條件時,q指向p的前一個節點地址
		p = p -> next;
	}

	q -> next = p -> next; 
	p -> next = NULL;     //斷開p指向的位元組在連邊中的連線順序
	free(p);    //釋放空間

}

//中間插, 新節點插到任意位置
void add_node(Link *head,Link m,int y) //需要討論head的指向,取二級指標,新節點的指標,插入節點的位置
{
	Link p,q;
	p = *head;

    	while(p -> num != (y - 1)) //指標p停在要插入位置的前一個節點
    	{
	    
	    	p = p -> next; 
    	}

     	q = p -> next;
	p -> next = m;
    	m -> next = q;

	m -> num = y;  //完成指標的指向操作
}
//指標num變數重賦值,
void replay_num(Link head)
{
	Link p;
	p = head;
    int i = 0;

	while(p != NULL)
	{
		p -> num = i + 1;
		p = p -> next;
		i++;
	}

}
 
//主函式
int main( )
{
	Link head = NULL;//head指向NULL 防止野指標
	Link p = NULL; //定義一個指標P指向NULL,防止野指標
	int k,x,y = 0,i = 0;
	Link m = NULL; //防止野指標

	creat_node(&head); //head指向一個空

        printf("請輸入姓名:\n");
	for(i = 0;i < 3;i++)
	{
                p = (Link)malloc(sizeof(Node)); //malloc()函式分配Node大小的空間,型別轉換為Link型,指賦給p
		
		if(p == NULL)//空間分配失敗
		{
			printf("malloc error!\n");
			exit(-1);  //結束程序 檔案包含stdlib.h
		}

		p -> num = i + 1;
		scanf("%s",p -> name);

	//	insert_head(&head,p); //頭插
		insert_tail(&head,p); //尾插
	}

	display_node(head);

        printf("連結串列長度:%d\n",length_node(head));

	printf("請輸入想要查詢的節點:\n");
	scanf("%d",&k);
	check_node(head,k);

	printf("請輸入想要刪除的節點:\n");
	scanf("%d",&x);
        delete_node(head,x);

	display_node(head); 

	m = (Link)malloc(sizeof(Node)); //m指向一個新分配的空間
        printf("請輸入想要插入的節點內容:\n");
	scanf("%s",m -> name);
	printf("請輸入想要插入的節點位置:\n");
	scanf("%d",&y);
	add_node(&head,m,y);

	replay_num(head); //呼叫add_node()函式後把num的內容重新排序

        display_node(head);


	release_node(head); //釋放函式要放在最後 所有操作結束後釋放空間
    return 0;
}