1. 程式人生 > >【C】單鏈表的簡單實現和應用!!!

【C】單鏈表的簡單實現和應用!!!

在單鏈表裡面,每個節點包含一個指向下一個節點 的指標。連結串列的最後一個節點的指標欄位是一個值為NULL的指標,他的作用就是提示連結串列後面不再有其他的節點。在你找到連結串列的第一個節點的時候呼叫節點裡面的指標就可以依次訪問剩下所有的節點。為了記住連結串列的起始位置,可以用一個根根指標。根指標指向連結串列的第一個節點,注意這裡根指標只是一個指標,它不包含其他的任何資料。它的作用僅僅就是指向連結串列的開始節點,呼叫根指標就可以訪問連結串列的節點。


struct  Stu
{
	char data[100];
	struct Stu *next;    //定義一個指向下一個節點的指標
};

在單鏈表裡面,當每次建立一個節點的時候,可以將資料儲存在節點的資料域,但是同時還需要將建立的新節點的地址賦給上個節點的next指標和將新節點的next指標置為NULL。

單鏈表的建立:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
typedef struct  Node
{
	char data;
	struct Node *next;
}Node;
int main()
{
	char ch = 0;
	Node *root = NULL;
	Node *p2 = NULL;
	Node* p1 = NULL;
	while (ch = getchar())
	{
		p1 = malloc(sizeof(Node));    //Set up a new node
		if (p1 == NULL)
		{
			return ;
		}
		if (root == NULL)
		{
			p1->data = ch;            //put ch to data
			root = p1;                // put address to root
			p1->next = NULL;         //set next 
		}
		else
		{
			p2->next = p1;
			p2 = p1;                 //...
			p1->data = ch;
		}
	}

	free(p1);
	return 0;
}
註釋:在main函式裡面,先建立了root指標當建立的第一個節點時候,將第一個節點的地址賦給root,當建立的新節點不是第一個節點的時候,經過if語句的判斷,將新節點的地址賦給上一個節點的next指標,之後又將新節點p1賦給p2,當程式建立第二個節點的時候又可以將新建立的節點的地址重新賦給上一個節點。這樣重複建立建立連結串列的節點,同時也將我們要儲存的資料儲存到每個節點 的資料區。

連結串列的插入

連結串列的插入又可以分為兩類:連結串列的前面插入和後面插入

連結串列的後面插入:

void sll_list(Node **head,int num)
{
	Node *p = *head;
	Node *new = malloc(sizeof(Node));   //建立一個新節點
	if (new == NULL)
	{
		return ;                     //判斷新節點是否建立成功
	}
	new->data = num;                  //將要加入的資料賦值給資料區
	new->next = NULL;
	if (*head == NULL)
	{
		*head = new;                 //當頭指標為空時直接將新節點的地址賦給頭指標
	}
	else
	{
		while(p->next)
		{
			p = p->next;         //找到連結串列的尾節點
		}
		p->next = new;                //將新節點作為為節點
	}
}

連結串列的前面插入:
void  sll_list(Node **head,int num)
{
	Node*new = malloc(sizeof(Node));
	if (new == NULL)
	{
		return ;
	}
	new->data = num;
	new->next = NULL;
	if (*head == NULL)
	{
		*head = new;
	}
	else
	{
		new->next = *head;            //將新節點作為連結串列的第一個節點
		*head = new;
	}
}

在連結串列裡面刪除資料:
void All_detele_List(Node **head)
{
	Node *p = *head;
	while (p)
	{
		free(p);
		p = p->next;
	}
}

在連結串列裡面指定修改的資料:
void change_list(Node **head,int aim,int num)
{
	Node *tmp = NULL;
	Node *p = *head;
	assert(*head);
	while (p)
	{
		if (p->data == aim)        //在連結串列裡面找到資料所在的位置
		{
			p->data = num;
		}
		p = p->next;
	}
}

在連結串列裡面刪除所有的節點:
void SL_Clear(Node **p_list)  
{  
	Node* p = NULL;
	Node* q = NULL;

	p = *p_list;    
	while(p!=NULL)  
	{  
		q = p->next;//藉助於q儲存p的鏈域,否則釋放p後無法引用  
		free(p);  
		p = q;  
	}  
	*p_list = NULL;//將所指的連結串列指標設為NULL  
}
注意:這裡一定要free掉每個節點的空間,不然會出現記憶體洩露的問題

計算連結串列裡面的節點個數:

int return_number(Node ** head)
{
	int i = 0;                     //定義一個計數器
	Node *p = *head;
	assert(*head);
    while (p)                          //當p不為null的時候計數器加1
    {
		p = p->next;
		i++;
    }
	return i;
}

單鏈表的經典筆試題:

    題目:輸入一個複雜連結串列(每個節點中有節點值,以及兩個指標,一個指向下一個節點,另一個特殊指標指向任意一個節點),返回結果為複製後複雜連結串列的head。

方法1:連結串列遍歷一遍,key和value的值對應關係如下然後再遍歷一次連結串列,設定複製連結串列的next和random指標

copy_list(RandomListNode pHead)
        {
          HashMap<RandomListNode, RandomListNode> map=new HashMap<RandomListNode, RandomListNode>();
          RandomListNode cur=pHead;
          while(cur!=null){
              map.put(cur, new RandomListNode(cur.label));
              cur=cur.next;
          }
          cur=pHead;
          while(cur!=null){
              map.get(cur).next=map.get(cur.next);
              map.get(cur).random=map.get(cur.random);
              cur=cur.next;
          }
            return map.get(pHead);
        }

方法2:遍歷一次連結串列,將連結串列複製的副本節點放到自己後面,再從左到右遍歷一次連結串列,設定random指標。分離連結串列,返回。

RandomListNode *copyRandomList(RandomListNode *head) 
{  
        // write your code here  
        RandomListNode *p = head;  
        RandomListNode *dest, *t = NULL;  
        while (p != NULL) {  
            t = new RandomListNode(p->label);  
            t->next = p->next;  
            t->random = p->random;  
            p->next = t;  
            p = t->next; //取得源連結串列中的下一個結點  
        }  
          
        p = head;  
        while (p != NULL) {  
            t = p->next;  
            if (t->random != NULL) {  // 此處需要判斷源節點的random是否為空,如果不為空才需要更新  
                t->random = t->random->next;  
            }  
            p = t->next;  
        }  
          
        p = head;  
        dest = p->next;  
        while (p != NULL) {  
            t = p->next;  
            p->next = t->next; //新舊連結串列分離的舊(源)連結串列  
            p = t->next;  
            if (p != NULL) {  
                t->next = p->next;  //新舊連結串列分離的新連結串列  
            }  
        }  
          
        return dest;  
    }