數據結構基礎三-----之模塊一《離散存儲【鏈表】》

離散存儲【鏈表】

1.定義:

       n個結點離散分配
       彼此通過指針相連
       每個結點只有一個前驅結點,每個結點只有一個後續結點
       首結點沒有前驅結點,尾結點沒有後續結點               


2.專業術語:

      首結點:第一個存放有效數據的結點

      尾結點:最有一個存放有效數據的結點

      頭結點:頭結點的數據類型和首結點的類型是一樣的

                      首結點之前的結點//   第一個有效結點之前的那個指針

                      頭結點並不存放有效數據,也沒有存放整個鏈表中 結點的個數。

                      加頭結點的目的是爲了方便對鏈表的操作

      頭指針:指向頭結點的指針變量  鏈表的首位置

      尾指針:指向尾結點的指針變量

示例1:如何定義一個結點(每一個結點的類型如何表示)

typedef struct Node
{
  int data; //數據域
  struct Node * pNext; //指針域

//指針存儲的地址只能是 struct Node 類型。
//指針域指向的 是與 本身結點數據類型相同的下一個結點 所以數據類型是 struct Node *;
}NODE,*PNODE;

//NODE 等價於 struct Node,
//PNODE 等價於 struct Node *;


      

3.如果希望一個函數來對鏈表進行處理,我們至少需要接受鏈表的哪些信息:

          只需要一個參數:頭指針
          以爲我們通過頭指針可以推算出鏈表的其他所有參數
                    

4.分類:

         單鏈表:每個結點的指針域只指向後面的結點
         雙鏈表:每一個結點有兩個指針(指前指後) 
         循環鏈表:能通過任何一個結點找到其他所有的結點
         非循環鏈表

5.算法:

       遍歷
       查找
       清空
       銷燬
       求長度
       排序
       刪除結點

       插入結點


插入結點:(僞算法)

 

//第1種寫法
  r = p->pNext; 
   p->pNext = q; 
   q->pNext = r;

//第2種寫法
   q->pNext = p->pNext; 
   p->pNext = q;//(這兩行代碼不能倒過來)

/*

  q 本身就是結點的地址  q 指向的就是 結點

  q-> pNext 表示的就是結點的指針域  

  至於指針域中存放的下一個結點的地址是誰 稍加判斷就好了。

  最重要的!p->pNext //p所指向的結構體變量中 pNext 成員本身。
*/


刪除結點:(僞算法)

  r = p->pNext;
 p->pNext = p->pNext->pNext; 
  free(r);//這裏很重要 一定要記得釋放內存,防止內存 溢出

示例2:創建並遍歷一個鏈表,實現判斷是否爲空,求鏈表的長度查找刪除

仿JAVA中LinkedList對象部分功能的實現

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node
{
//數據域
	int data;
//指針域
	struct Node * pNext;
//指針域指向的 是與 本身結點數據類型相同的下一個結點 所以數據類型是 struct Node *;
}NODE,*PNODE;
//NODE 等價於 struct Node,
//PNODE 等價於 struct Node *;
//函數聲明
PNODE  create_list(void);
void traverse_list(PNODE pHead);
bool is_empty(PNODE pHead);
int length_list(PNODE);
bool insert_list(PNODE,int,int);
bool delete_list(PNODE,int,int *);
void sort_list(PNODE);

int main(void)
{
   PNODE pHead = NULL;//等價於 struct Node * pHead = NULL;
   //create_list()的功能:創建一個非循環單鏈表,並將該鏈表的頭結點的地址賦給 pHead
   pHead = create_list();
   traverse_list(pHead);//遍歷
   if(is_empty(pHead))
      printf("鏈表爲空\n");
   else
      printf("鏈表不空\n");
   int len = length_list(pHead);
   printf("鏈表的長度是%d \n",len);
   sort_list(pHead);
   traverse_list(pHead);//遍歷
   insert_list(pHead,2,33);
   traverse_list(pHead);//遍歷
   int val;
   if(delete_list(pHead,4,&val))
   {
      printf("您刪除的元素是%d\n",val);
   }
   else
   {
      printf("刪除失敗%d\n",val);
   }
   return 0;
}

//創建一個鏈表,創建一個非循環單鏈表,並將該鏈表的頭結點的地址賦給 pHead
PNODE  create_list(void)
{
   //C語言裏的寫法是把所有的變量都定義在前面
   int len;//用來存放有效結點的個數
   int i;
   int val;//用來存放用戶輸入的有效結點的值
   //升成一個頭結點  頭結點的數據類型與 其他結點是相同的。
   //分配了一個不存放有效數據的頭結點
   PNODE pHead = (PNODE)malloc(sizeof(NODE));
   if(NULL == pHead)
   {
      printf("分配失敗,程序終止。\n");
      exit(-1);
   }
   //pTail  永遠指向 尾結點
   PNODE pTail = pHead;
   pTail -> pNext = NULL;
   printf("請輸入您需要生成的鏈表的結點的個數:len =");
   scanf("%d",&len);
   for(i =0;i<len;++i)
   {
      printf("請輸入第%d個結點的值:",i+1);
      scanf("%d",&val);
      PNODE pNew  = (PNODE)malloc(sizeof(NODE));
      if(NULL == pNew)
      {
         printf("分配失敗,程序終止。\n");
         exit(-1);
      }
      pNew ->data = val;
      //新生成的結點要掛到整個鏈表的最後的一個位置。
      pTail -> pNext = pNew;
      pNew ->pNext = NULL;
      pTail = pNew;
      }
   return pHead;
}

//遍歷這個鏈表
void traverse_list(PNODE pHead)
{
//p 指向的是鏈表的第一個有效結點
   PNODE p  = pHead->pNext;
   while(p!= NULL)
   {
      printf("  %d",p->data);
      p = p->pNext;
   }
   printf("\n");
   return;
}

//判斷鏈表是否爲空
bool is_empty(PNODE pHead)
{
   if(pHead->pNext == NULL)
      return true;
   else
      return false;
}

//返回鏈表長度
int length_list(PNODE pHead)
{
   PNODE p = pHead ->  pNext;
   int len = 0;
   while(p != NULL)
   {
      len++;
      p = p->pNext;
   }
   return len;
}

//鏈表排序
void sort_list(PNODE pHead)
{	
  //實際上算法都是類似
  //數組和鏈表同樣都是 線性結構
   int i,j,t;
   PNODE p, q;
   int len = length_list(pHead);
   //i 是數組中第一個有效元素的下標  p 是鏈表中第一個有效元素的 地址。
   for(i = 0,p = pHead ->pNext;i<len - 1;++i,p = p->pNext)
   {
   //  q 就應該是p 的下一個元素
      for(j = i+1,q = p ->pNext;j<len;++j,q = q->pNext)
      {
	/*
	請參照數組中的方式來理解 鏈表
	if(a[i] > a[j])
	{
	   t = a[i];
	   a[i] = a[j];
	   a[j] = t;
	}
	*/
	if((p->data )> (q->data))
	{
	   t = p->data;
	   p->data = q->data;
   	   q->data= t;
	}
      }
   }
	return;
}

//在pHead 所指向鏈表的第pos 個結點的前面插入一個新的結點,該結點的值是 val並且 pos 的值是從1 開始。
bool insert_list(PNODE pHead,int pos,int val)
{
   int i = 0;
   PNODE  p = pHead;
   while(p != NULL && i<pos -1)
   {
      p = p->pNext;
      i++;
   }
   if(i>pos-1||p== NULL)
      return false;
   PNODE pNew = (PNODE)malloc(sizeof(PNODE));
   if(pNew == NULL)
   {
      printf("動態分配內存失敗");
      exit(-1);
   }
   pNew ->data = val;
   //定義了一個臨時結點
   PNODE q = p->pNext;
   p->pNext = pNew;
   pNew ->pNext = q;
   return true;
}

//刪除指定位置的元素,並用*pVal記錄被刪除的元素
bool delete_list(PNODE pHead,int pos,int * pVal)
{
   int i = 0;
   PNODE  p = pHead;
   while(p ->pNext!= NULL && i<pos -1)
   {
      p = p->pNext;
      i++;
   }
   if(i>pos-1||p ->pNext== NULL)
      return false;
   PNODE q = p ->pNext;
   *pVal = q ->pNext;
  //刪除p結點後面的結點
   p->pNext = p->pNext->pNext;
   free(q);
   q = NULL;
   return true;
}

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