1. 程式人生 > >連結串列(陳銳、葛麗萍編著《跟我學資料結構》整理

連結串列(陳銳、葛麗萍編著《跟我學資料結構》整理

  連結串列通過自引用結構體型別的指標成員指向結構體本身建立起來,“自引用結構體”包含一個指標成員,該指標指向與結構體一樣的型別。

struct node 
{
    int data;//整形成員
    struct node *next;//指標成員
};

自引用結構體單元稱為節點,jie'結點之間通過箭頭連線qi'l起來,構成一個表,成為連結串列。

連結串列中zhi'指向第一個節點的指標chen成為頭指標,tong通過頭指標,可以訪問連結串列的每一個結點。

連結串列的最後一個節點的指標部分用空(NULL)表示。

為了方便,在連結串列的第一個結點之前增加一個結點,稱為tou'頭結點。

不帶頭節點的指標   head ->[a   ]->[b   ]->[c   ]->[d  ^]      

帶頭節點de'z的指標 head->[      ]->[a    ]->[b    ]->[c   ]->[d   ^]

單鏈表的儲存結構

typedef struct Node
{
    DataType data;
    struct Node *next;
} ListNode,*LinkList;

其中,ListNode是lian連結串列的結點型別,LinkList 是指向連結串列節點的指標型別

定義LinkList L;定義了一個連結串列,L指向該連結串列的第一個結點,對於不帶頭結點的連結串列來說,如果連結串列為空,則有L=NULL;

對於帶頭結點的連結串列,如果連結串列為空,則L->next=NULL;

單鏈表上的基本運算

1.單鏈表的初始化

void InitList(LinkList *head)
//將單鏈表初始化為空,動態生成一個頭節點,並將頭結點的指標域置為空。
{
   if((*head=(LinkList)malloc(sizeof(ListNode)))==NULL)//為頭節點分配一個儲存空間。
        exit(-1);
   (*head)->next=NULL;//將單鏈表的頭結點的指標域置為空
}

2.判斷單鏈表是否為空,

int ListEmpty(LinkList head)
//判斷單鏈表是否為空,通過判斷頭結點的指標域是否為空
{
    if(head->next==NULL)//判斷單鏈表頭結點的指標域是否為空。
        return 1;
    else
        return 0;
}

3.按序號查詢操作

///按序號查詢操作;從頭指標head出發,利用節點的next 域,掃描連結串列的結點。
ListNode* Get(LinkList head,int i)
{
    ListNode *p;
    int j;
    if(ListEmpty(head)) return NULL;
    if(i<1) return NULL;
    j=0;
    p=head;
    while(p->next!=NULL&&j<i)
    {
        p=p->next;
        j++;
    }
    if(j==i)  return  p;
    else return NULL;
}

4.///按內容查詢操作

///按內容查詢操作
ListNode* LocateElem(LinkList head,DataType e)
{
    ListNode *p;
    p=head->next;
    while(p)
    {
        if(p->data !=e)
            p=p->next;
        else
            break;
    }
    return p;
}

5。定位操作

int LocatePos(LinkList head,DataType e)
{
    ListNode *p;
    int i;
    if(ListEmpty(head))  return 0;
    p=head->next;///p指向第一個節點
    i=1;
    while(p)
    {
        if(p->data==e)  return i;
        else
        {
            p=p->next;
            i++;
        }
    }
    if(!p) ///沒有找到與e相等的元素,表示失敗,返回0;
    return 0;
}

6.cha'插入操作

///插入操作,在單鏈表的第i個位置插入一個節點,節點元素的值為e,插入成功返回1,插入失敗返回0;
int InsertList(LinkList head,int i,DataType e)
{
    ListNode *p,*pre;
    ///定義指向第i個元素的前驅結點指標pre,指標p指向新生成的結點
    int j;
    pre=head;
    j=0;
    while(pre->next!=NULL&&j<i-1)
    {
        pre=pre->next;
        j++;
    }
    if(j!=i-1)
    {
        printf("插入位置錯誤");
        return 0;
    }
    //x新生成一個結點,並將 E賦值給該i節點的資料域
    if((p=(ListNode*)malloc(sizeof(ListNode)))==NULL)
        exit(-1);
        ///插入節點操作;
    p->data=e;
    p->next=pre->next;
    pre->next=p;
    return 1;
}

7.刪除操作

int DeleteList(LinkList head,int i,DataType *e)
{
    ListNode *pre,*p;
    int j;
    pre=head;
    j=0;
    while(pre->next!=NULL&&pre->next->next!=NULL && j<i-1)
    {
        pre=pre->next;
        j++;
    }
    if(j!=i-1)
    {
        printf("刪除位置錯誤");
        return 0;
    }
    ///刪除操作
    ///指標p指向單鏈表中的第i個結點,並將該節點的資料域值賦值給E
    p=pre->next;
    *e=p->data;
    pre->next=p->next;
    free(p);
    return 1;
}

8.求表長

///求表長操作
int ListLength(LinkList head)
{
    ListNode *p;
    int count = 0;
    p=head;
    while(p->next!=NULL)
    {
        p=p->next;
        count++;
    }
    return count;
}

9.銷燬連結串列

///銷燬連結串列操作
void DestroyList (LinkList head)
{
    ListNode *p,*q;
    p=head;
    while(p!=NULL)
    {
        q=p;
        p=p->next;
        free(q);
    }
}

應用舉例:單鏈表應用舉例:實現如果單鏈表A中出現的元素在單鏈表B中也出現,則將A中該元素刪除。

///l單鏈表應用舉例:
#include <iostream>
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef int DataType;
typedef struct Node
{
    DataType data;
    struct Node *next;
} ListNode,*LinkList;
//單鏈表上的基本運算
void InitList(LinkList *head)
//將單鏈表初始化為空,動態生成一個頭節點,並將頭結點的指標域置為空。
{
   if((*head=(LinkList)malloc(sizeof(ListNode)))==NULL)//為頭節點分配一個儲存空間。
        exit(-1);
   (*head)->next=NULL;//將單鏈表的頭結點的指標域置為空
}
int ListEmpty(LinkList head)
//判斷單鏈表是否為空,通過判斷頭結點的指標域是否為空
{
    if(head->next==NULL)//判斷單鏈表頭結點的指標域是否為空。
        return 1;
    else
        return 0;
}
///按序號查詢操作;從頭指標head出發,利用節點的next 域,掃描連結串列的結點。
ListNode* Get(LinkList head,int i)
{
    ListNode *p;
    int j;
    if(ListEmpty(head)) return NULL;
    if(i<1) return NULL;
    j=0;
    p=head;
    while(p->next!=NULL&&j<i)
    {
        p=p->next;
        j++;
    }
    if(j==i)  return  p;
    else return NULL;
}
///按內容查詢操作
ListNode* LocateElem(LinkList head,DataType e)
{
    ListNode *p;
    p=head->next;
    while(p)
    {
        if(p->data !=e)
            p=p->next;
        else
            break;
    }
    return p;
}
int LocatePos(LinkList head,DataType e)
{
    ListNode *p;
    int i;
    if(ListEmpty(head))  return 0;
    p=head->next;///p指向第一個節點
    i=1;
    while(p)
    {
        if(p->data==e)  return i;
        else
        {
            p=p->next;
            i++;
        }
    }
    if(!p) ///沒有找到與e相等的元素,表示失敗,返回0;
    return 0;
}
///插入操作,在單鏈表的第i個位置插入一個節點,節點元素的值為e,插入成功返回1,插入失敗返回0;
int InsertList(LinkList head,int i,DataType e)
{
    ListNode *p,*pre;
    ///定義指向第i個元素的前驅結點指標pre,指標p指向新生成的結點
    int j;
    pre=head;
    j=0;
    while(pre->next!=NULL&&j<i-1)
    {
        pre=pre->next;
        j++;
    }
    if(j!=i-1)
    {
        printf("插入位置錯誤");
        return 0;
    }
    //x新生成一個結點,並將 E賦值給該i節點的資料域
    if((p=(ListNode*)malloc(sizeof(ListNode)))==NULL)
        exit(-1);
        ///插入節點操作;
    p->data=e;
    p->next=pre->next;
    pre->next=p;
    return 1;
}
int DeleteList(LinkList head,int i,DataType *e)
{
    ListNode *pre,*p;
    int j;
    pre=head;
    j=0;
    while(pre->next!=NULL&&pre->next->next!=NULL && j<i-1)
    {
        pre=pre->next;
        j++;
    }
    if(j!=i-1)
    {
        printf("刪除位置錯誤");
        return 0;
    }
    ///刪除操作
    ///指標p指向單鏈表中的第i個結點,並將該節點的資料域值賦值給E
    p=pre->next;
    *e=p->data;
    pre->next=p->next;
    free(p);
    return 1;
}

///求表長操作
int ListLength(LinkList head)
{
    ListNode *p;
    int count = 0;
    p=head;
    while(p->next!=NULL)
    {
        p=p->next;
        count++;
    }
    return count;
}
///銷燬連結串列操作
void DestroyList (LinkList head)
{
    ListNode *p,*q;
    p=head;
    while(p!=NULL)
    {
        q=p;
        p=p->next;
        free(q);
    }
}
void DelElem(LinkList *A ,LinkList B)//解決問題的函式
{
    int i,pos;
    DataType e;
    ListNode *p;
    for(i=1;i<=ListLength(B);i++)
    {
        p=Get(B,i);
        if(p)
        {
           pos=LocatePos(*A,p->data);
           if(pos>0) DeleteList(*A,pos,&e);
        }
    }
}
using namespace std;

int main()
{
    int i;
    DataType a[]={6,7,9,14,37,45,65,67};
    DataType b[]={3,7,11,34,45,89};
    LinkList A,B,C;
    ListNode *p;
    InitList(&A);
    InitList(&B);
    InitList(&C);
    for(i=1;i<=sizeof(a)/sizeof(a[0]);i++)
    {
        if(InsertList(A,i,a[i-1])==0)
        {
            printf("位置不合法");
            return 0 ;
        }
    }
    for(i=1;i<=sizeof(b)/sizeof(b[0]);i++)
    {
        if(InsertList(B,i,b[i-1])==0)
        {
            printf("位置不合法");
            return 0;
        }
    }
    printf("A中的元素有%d個\n",ListLength(A));
    for(i=1;i<=ListLength(A);i++)
    {
        p=Get(A,i);
        if(p)
            printf("%4d",p->data);
    }
    printf("\n");
    printf("單鏈表B中的元素有 %d個:\n",ListLength(B));
    for(i=1;i<=ListLength(B);i++)
    {
        p=Get(B,i);
        if(p)
            printf("%4d",p->data);
    }
    printf("\n");
    DelElem(&A,B);
    printf("將在A中出現B的元素刪除後,現在A 中的元素還有%d個:\n",ListLength(A));
    for(i=1;i<=ListLength(A);i++)
    {
        p=Get(A,i);
        if(p)
            printf("%4d",p->data);
    }
    return 0;
}