C+數據結構與算法之鏈表之單鏈表

1.單鏈表定義

每一個節點包括一個數據域一個指針域,節點在內存中地址能夠不連續,可是節點內部地址必然連續。
圖片描述node

2.結構定義

typedef struct Lnode{
int data;
struct Lnode *next;
}Lnode,*LinkList;

3.單鏈表的建立

1)頭插法
每次將s指向節點放在最前面,因此與輸入順序相反,先找到下一節點再解鏈算法

//頭插法創建帶頭結點的單鏈表
LinkList create1(LinkList &L){
  Lnode *s;
  int x; 
  L=(LinkList) malloc( sizeof(Lnode));//建立頭結點
  L->next = NULL; //初始化
  printf("往鏈表中添加數據,99999結束\n");
  scanf("%",&x);
  while(x!=99999){
      s = (Lnode*)malloc(sizeof(Lnode));//建立新節點
      s->data = x;
      s->next = L->next;
      L->next = s;
      scanf("%d",&x);
       
  }


return L;
}

2)尾插法
每次插入節點都在鏈表最後,因此與輸入順序相同,不用先解鏈,只用把尾指針不斷指向新的表尾節點函數

//尾插法創建單鏈表
LinkList create2(LinkList &L){

    int x;
    L=(LinkList) malloc( sizeof(Lnode));//建立尾結點
    Lnode *s,*r = L;//S爲插入節點指針,r爲尾指針
printf("往鏈表中添加數據,99999結束\n");
    //scanf("%",&x);
    while(x!=99999){
      s = (Lnode*)malloc(sizeof(Lnode));//建立新節點
      scanf("%d",&x); 
      s->data = x;
      r->next = s;
      r = s; //r指向新的表尾
      
    }
    r->next = NULL;//尾節點指針置空
    return L;
}

4.單鏈表的查找

1)按值查找spa

//按值查找表節點,返回節點位序,查找失敗返回-1
int locateElem(LinkList L, int e){
    Lnode *P = L->next;
    int j=1;
    while (P!=NULL&&P->data!=e){
      P = P->next;
      j++;
    }
     if(P->next == NULL && P->data == e)
    return j;
    else if(P->next != NULL && P->data == e)
    return j;
    else
        return -1;
}
//按值查找表節點,返回節點指針,這是方便鏈表運算實現
Lnode *locateElem2(LinkList L, int e){
 Lnode *P = L->next;
    while (P!=NULL&&P->data!=e){
      P = P->next;
    }
    return P;//失敗則返回空指針
}

2)按序號查找指針

//按序號查找表節點,返回節點值
int getElem(LinkList L,int i){
    int j = 1;
    Lnode *P = L->next;
    if(i==0)
        return 0;//若是i=0,則返回頭結點的值,但頭結點不存值故返回0
    if(i<0)
        return -1;//錯誤序號則返回-1
    while(P&&j<i)//P非空
    {
       P= P->next;
       j++;
    }
   return P->data;
}

//按序號查找表節點,返回節點指針,這是方便鏈表運算實現
Lnode *getElem1(LinkList L, int i){
   int j = 1;
    Lnode *P = L->next;
    if(i==0)
        return L;//若是i=0,則返回頭結點
    if(i<0)
        return NULL;//錯誤序號則返回NULL
    while(P&&j<i)//P非空
    {
       P= P->next;
       j++;
    }
   return P;
}

4.單鏈表表長

int getLength(LinkList L){
   int count = 0;
   while(L->next->next!=NULL)//此處指針因人而異,思想就是尾節點指針爲空結束循環
   {
       L = L->next;
    count ++;
   }
   return count;
}

5.插入節點

//插入節點算法1(後插,前插通常不考慮)
//指定位置插入節點
int insertElem1(LinkList L,int i,int e){
    if (i<=1||i>getLength(L))
    {
    return 0;
    }
    else
    {
   Lnode *s,*p;
   p = getElem1(L,i-1);//獲取插入位置前驅
   s = (Lnode*)malloc(sizeof(Lnode));//建立新節點
   s->data = e;
   s->next = p->next;//此句和下面那句代碼不可顛倒,單鏈表只可找到後繼,因此後繼指針不能被先覆蓋
   p->next = s;
   return 1;
    }
}

//插入節點算法2
//只交換數據,不改變指針,在已知節點位置的基礎上這個是最優算法
int insertElem2(LinkList L,int i,int e){
    int temp;
    if (i<=1||i>getLength(L))
    {
    return 0;
    }
    else
    {
   Lnode *s,*p;
   p = getElem1(L,i);//獲取插入位置前驅
   s = (Lnode*)malloc(sizeof(Lnode));//建立新節點
   s->data = e;
   s->next = p->next;
   p ->next = s;
    temp = p->data;//這裏作個數據交換
   p->data = s->data;
   s->data = temp;  
   return 1;
    }
}

6.完整代碼

#include <stdio.h>
#include <stdlib.h>//malloc函數頭文件
//單鏈表定義
typedef struct Lnode{

int data;
struct Lnode *next;
}Lnode,*LinkList;

//頭插法創建帶頭結點的單鏈表
LinkList create1(LinkList &L){
  Lnode *s;
  int x; 
  L=(LinkList) malloc( sizeof(Lnode));//建立頭結點
  L->next = NULL; //初始化
  printf("往鏈表中添加數據,99999結束\n");
  scanf("%",&x);
  while(x!=99999){
      s = (Lnode*)malloc(sizeof(Lnode));//建立新節點
      s->data = x;
      s->next = L->next;
      L->next = s;
      scanf("%d",&x);
       
  }


return L;
}
  //尾插法創建單鏈表
LinkList create2(LinkList &L){

    int x;
    L=(LinkList) malloc( sizeof(Lnode));//建立尾結點
    Lnode *s,*r = L;//S爲插入節點指針,r爲尾指針
printf("往鏈表中添加數據,99999結束\n");
    //scanf("%",&x);
    while(x!=99999){
      s = (Lnode*)malloc(sizeof(Lnode));//建立新節點
      scanf("%d",&x); 
      s->data = x;
      r->next = s;
      r = s; //r指向新的表尾
      
    }
    r->next = NULL;//尾節點指針置空
    return L;
}

//求單鏈表表長
int getLength(LinkList L){
   int count = 0;
   while(L->next->next!=NULL)
   {
       L = L->next;
    count ++;
   }
   return count;
}
//按序號查找表節點,返回節點值
int getElem(LinkList L,int i){
    int j = 1;
    Lnode *P = L->next;
    if(i==0)
        return 0;//若是i=0,則返回頭結點的值,但頭結點不存值故返回0
    if(i<0)
        return -1;//錯誤序號則返回-1
    while(P&&j<i)//P非空
    {
       P= P->next;
       j++;
    }
   return P->data;
}

//按序號查找表節點,返回節點指針,這是方便鏈表運算實現
Lnode *getElem1(LinkList L, int i){
   int j = 1;
    Lnode *P = L->next;
    if(i==0)
        return L;//若是i=0,則返回頭結點
    if(i<0)
        return NULL;//錯誤序號則返回NULL
    while(P&&j<i)//P非空
    {
       P= P->next;
       j++;
    }
   return P;
}

//按值查找表節點,返回節點位序,查找失敗返回-1
int locateElem(LinkList L, int e){
    Lnode *P = L->next;
    int j=1;
    while (P!=NULL&&P->data!=e){
      P = P->next;
      j++;
    }
     if(P->next == NULL && P->data == e)
    return j;
    else if(P->next != NULL && P->data == e)
    return j;
    else
        return -1;
}
//按值查找表節點,返回節點指針,這是方便鏈表運算實現
Lnode *locateElem2(LinkList L, int e){
 Lnode *P = L->next;
    while (P!=NULL&&P->data!=e){
      P = P->next;
    }
    return P;//失敗則返回空指針
}

//插入節點算法1(後插,前插通常不考慮)
//指定位置插入節點
int insertElem1(LinkList L,int i,int e){
    if (i<=1||i>getLength(L))
    {
    return 0;
    }
    else
    {
   Lnode *s,*p;
   p = getElem1(L,i-1);//獲取插入位置前驅
   s = (Lnode*)malloc(sizeof(Lnode));//建立新節點
   s->data = e;
   s->next = p->next;//此句和下面那句代碼不可顛倒,單鏈表只可找到後繼,因此後繼指針不能被先覆蓋
   p->next = s;
   return 1;
    }
}

//插入節點算法2
//只交換數據,不改變指針,在已知節點位置的基礎上這個是最優算法
int insertElem2(LinkList L,int i,int e){
    int temp;
    if (i<=1||i>getLength(L))
    {
    return 0;
    }
    else
    {
   Lnode *s,*p;
   p = getElem1(L,i);//獲取插入位置前驅
   s = (Lnode*)malloc(sizeof(Lnode));//建立新節點
   s->data = e;
   s->next = p->next;
   p ->next = s;
    temp = p->data;//這裏作個數據交換
   p->data = s->data;
   s->data = temp;  
   return 1;
    }
}


int main(){
    LinkList L,L1;
    /*
    create1(L);
     LinkList temp = L->next;
    while(temp->next != NULL)
    {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("頭插法與存數據的順序相反\n");
*/
    create2(L1);
    LinkList temp2 = L1->next;
     while(temp2 ->next != NULL)
    {
        printf("%d ", temp2->data);
        temp2 = temp2->next;
    }
    printf("尾插法與存數據的順序相同\n");
    int length;
    length = getLength(L1);
    printf("單鏈表長度爲:%d\n",length);
    /*
     printf("輸入取值位序\n");
     int i;
      scanf("%d",&i);
      printf("第%d位值爲%d\n",i, getElem(L1,i));

      printf("輸入查找值\n");
     int e;
      scanf("%d",&e);
      printf("值爲:%d位序爲:%d\n",e, locateElem(L1,e));
      */
      //插入節點算法1
      /*
      int x1,x2;
       printf("插入節點算法1\n");
       printf("插入位置:");
        scanf("%d",&x1);
        printf("插入值:");
        scanf("%d",&x2);
        int desert = insertElem1(L1,x1,x2);
        if(desert == 1)
        {
           printf("插入成功\n");
           LinkList temp3 = L1->next;
        }
        else
        {
            printf("插入失敗,位置不合法\n");
        }
         printf("打印鏈表(插入算法1)\n");
         LinkList temp3 = L1->next;
     while(temp3 ->next != NULL)
    {
        printf("%d ", temp3->data);
        temp3 = temp3->next;
    }
*/
      //插入節點算法2
      int x3,x4;
       printf("插入節點算法2\n");
       printf("插入位置:");
        scanf("%d",&x3);
        printf("插入值:");
        scanf("%d",&x4);
        int desert1 = insertElem2(L1,x3,x4);
        if(desert1 == 1)
        {
           printf("插入成功\n");
           LinkList temp4 = L1->next;
        }
        else
        {
         printf("插入失敗,位置不合法\n");
        }
         printf("打印鏈表(插入算法2)\n");
         LinkList temp4 = L1->next;
     while(temp4 ->next != NULL)
    {
        printf("%d ", temp4->data);
        temp4 = temp4->next;
    }
return 0;
}

7.小結

單鏈表做爲鏈表中最簡單的一種,擺脫了順序表對空間的束縛,能夠很好的支持動態操做。可是其問題也很明顯,每一個節點只能找到其直接後繼,而找不到其前一節點。在查找時須要從表頭開始遍歷表,會增長時間複雜度。code

相關文章
相關標籤/搜索