1. 程式人生 > >數據結構——鏈表

數據結構——鏈表

ali for 單元 遍歷 next != com 發生 src

頭指針或者尾指針需要改變,並且需要把改變的值帶回到主程序,帶回到調用處需要用的指針的指針;
當尾指針不發生改變,或者即使發生了改變也不希望帶回到主程序當中就用指針;

1 鏈式存儲結構

特點:用一組任意的存儲單元存儲線性表中的數據元素;這組存儲單元可以使連續的也可以是不連續的;每個數據元素除了存儲數據外,還要存儲前驅、後繼元素的地址。

每個元素包括數據域和指針域;存儲數據的部分就是數據域,存儲地址的部分就是指針域;

data address
數據域 指針域

2 單鏈表

n個節點按鏈式存儲結構存儲,每個節點只包含一個指針域;

技術分享圖片

技術分享圖片

2.1 線性表的單鏈表存儲結構

typedef int DataType;
typedef struct Node
{
  DataType data;
  struct Node *next;
}Node;

2.2 獲取指定位置的元素

typedef int DataType;
typedef struct Node
{
  DataType data;
  struct Node *next;
}Node;

Node* getptr(Node* head,int pos)
{
   Node *p=head;
  if(p==NULL || pos==0)
  {
    return head;
  }
  for
(int i=0;p&&i<pos;i++) p=p->next; return p; } void main() { Node *head=NULL; ... Node *p=getptr(head,3); //獲取第3個節點的元素 }

2.3 獲取單鏈表中節點個數

typedef int DataType;
typedef struct Node
{
  DataType data;
  struct Node *next;
}Node;

int getSize(Node* head)
{
  int size=0;
  Node *p=head;
  
while(p) //直到p指向的節點地址域為空時,停止循環,返回size { size++; p=p->next; } return size; } void main() { Node *head=NULL; ... int len=getSize(head); //獲取第3個節點的元素 }

技術分享圖片

2.4 單鏈表插入節點

typedef int DataType;
typedef struct Node
{
  DataType data;
  struct Node *next;
}Node;

bool insert(Node**head,int position,DataType d)
{
  if(position<0||position>getSize(*head))
    return false;
  Node *node=(Node*)malloc(sizeof(Node));
  node->next=NULL;
  node->next=d;
  if(position==0)   //if中的語句實現插入空鏈表或頭部
  {
    node->next=*head;
    *head=node;
    return true;
  }
  Node *p=getptr(*head,position-1); //以下5條語句實現插入中間或者尾部
  Node *r=p->next;
  node->next=r;
  p->next=node;
  return true;
}

void main()
{
  Node *head=NULL;
  ...
  insert(&head,0,10); //頭部或者空表插入數據10
  insert(&head,3,7); //第3個節點插入數據7
}

技術分享圖片

2.5 單鏈表刪除

bool erase(Node **head,int pos)
{
  if(pos<0 || pos>getSize(*head))
    return false;
  Node *p=*head;
  if(pos==0)
  {
    *head=(*head)->next;
    free(p);    //是否指針p,即刪除p指向的節點
    p=NULL;  //節點不存在就讓它為空,防止出現意外
    return true;
  }
  p=getptr(*head,pos-1);
  Node *q=p->next;
  p->next=q->next;
  free(q);
  q=NULL;

  return true;
}

void main()
{
  Node *head=NULL;
  insert(&head,0,10);
  insert(&head,0,8);
  insert(&head,0,3);
  insert(&head,0,5);
  erase(&head,0);
  erase(&head,1);
}

2.6 將兩個線性鏈表合並

void union(Node *a,Node *b)
{
  Node *p=*a;
  if(p->next)
    p=p->next;
  p->next=b;
}

void main()
{
  Node *ahead=NULL;
  Node *bhead=NULL;
  insert(&ahead,0,10);
  insert(&ahead,0,3);
  insert(&ahead,0,8);
  insert(&ahead,0,5);
  insert(&bhead,0,7);
  insert(&bhead,0,6);
  insert(&bhead,0,2);
  insert(&bhead,0,4);
  union(ahead,bhead);
}

2.7 線性鏈表的倒置

void reverse(Node **head)
{
  Node *p=*head;
  Node *q=p->next;
  if(q==NULL)
    return;
  Node *r=q->next;
  if(p==*head) //可以不要,最好不要
    p->next=NULL;
  while(true)
  {
    q->next=p;
    if(r==NULL)
    {
      *head=q;
      break;
    }
    elase
    {
      p=q;
      q=r;
      r=r->next;
    }
  }
}

void main()
{
  Node *head=NULL;
  insert(&head,0,10);
  insert(&head,0,3);
  insert(&head,0,8);
  insert(&head,0,8);
  reverse(&head);
}

技術分享圖片

技術分享圖片

2.8 線性鏈表的遍歷

void print(DataType d)
{
  printf("%d\n",d);
}

void trave(Node *head,void(*fun)(DataType))
{
  Node *p=head;
  while(p)
  {
    fun(p->data);
    p=p->next;
  }
}

void main()
{
  Node *head=NULL;
  insert(&head,0,10);
  insert(&head,0,3);
  insert(&head,0,8);
  insert(&head,0,8);
  trave(head,print);
}

3 單循環鏈表

循環鏈表:

將單鏈表中最後一個節點的指針域由空改為指向第一個節點,使整個單鏈表形成一個環;

技術分享圖片

3.1 線性表的單循環列表存儲結構

typedef int DataType 
typedef struct Node
{
  DataType data;
  struct Node *next;
}Node;

3.2 獲取單循環鏈表中的節點個數

typedef int DataType 
typedef struct Node
{
  DataType data;
  struct Node *next;
}Node;

int getSize(Node *rear)
{
  int size=0;
  if(rear)
  {
    Node *p=rear->next;
    while(p!=rear)
    {
      size++;
      p=p->next;
    }
    size++;
  }
  return size;
}

void main()
{
  Node *rear=NULL; //定義尾指針指向單鏈表最後一個節點,rear->next會指向頭指針,相當於頭指針
  ...
  int len=getSize(rear);
}

3.3 獲取指定位置的元素

typedef int DataType 
typedef struct Node
{
  DataType data;
  struct Node *next;
}Node;

Node *getptr(Node *rear,int pos)
{
  if(rear==NULL)
    return rear;
  if(pos<0 || pos>=getSize(rear))
    return NULL;
  Node *p=rear->next;
  for(int i=0;i<pos;i++)
    p=p->next;
  return p;
}

void main()
{
  Node *rear=NULL; 
  ...
  Node *p=getptr(rear,2);
}

3.4 單循環鏈表插入節點

typedef int DataType 
typedef struct Node
{
  DataType data;
  struct Node *next;
}Node;

bool insert(Node **rear,int position,DataType d)
{
  if(position<0 || position>getSize(*head))
    return false;
  Node *node=(Node*)malloc(sizeof(Node));
  node->data=d;
  node->next=NULL;
  if(position==0)
  {
    if(*rear==NULL)
    {
      node->next=node;
      *rear=node;
    }
    else
    {
      node->next=(*rear)->next;
      (*rear)->next=node;
    }
    return true;
  }
  Node *p=getptr(*head,position-1);
  Node *r=p->next;
  node->next-r;
  p->next=node;
  if(*rear=p)
  {
    *rear=node;
  }
  return ture;
}

void main()
{
  Node *rear=NULL;
  insert(&rear,0,10);
  insert(&rear,0,3);
  insert(&rear,0,8);
  insert(&rear,1,5);
}

3.5 單循環列表的刪除

bool erase(Node **rear,int pos)
{
  if(*rear==NULL || pos<0 || pos>getSize(*head))
    return false;
  Node *p=(*rear)->next;
  if(pos==0)
  {
    (*rear)->next=p->next;
    free(p);    //是否指針p,即刪除p指向的節點
    p=NULL;  //節點不存在就讓它為空,防止出現意外
    return true;
  }
  p=getptr(*rear,pos-1);
  Node *q=p->next;
  p->next=q->next;
  if(q==*rear)
    *rear=p;
  free(q);
  q=NULL;

  return true;
}

void main()
{
  Node *rear=NULL;
  insert(&rear,0,10);
  insert(&rear,0,8);
  insert(&rear,0,3);
  insert(&rear,0,5);
  erase(&rear,0);
  erase(&rear,1);
}

數據結構——鏈表