線性表的鏈式存儲與十三種運算操作

線性表的鏈式存儲與運算實現

1 先修知識

1.1 malloc與new的區別

new會自動根據類型分配內存地址,並返回同類型的指針給引用

int *p1,*p2;
p1 = new int;
p2 = new int[100];

malloc只能動態分配內存,意思就是不會自動分配,必須人爲設定內存大小與返回的指針類型

int *p;
p = (int*)malloc(sizeof(int)*100);

1.2 ->的用法

->是間接引用符,是二目訪問符,類似於成員符 .

typedef struct Node{
    int a;
    double b;
}node, *linkList;
*linkList = &node;
//struct Node *p = &node;
//此時
linkList->a等價於(*linkList).a;

1.3 struct的用法

自定義類型struct

typedef struct Node{
    Elemtype a;
    Node *next;
}node,linkList; //結構變量node等有點像靜態類,這裏借用java編程思想描述,Node是父類,node,linkList是子類.
或
struct Node node,linkList;//按模板類型Node定義具體類型node,linkList

寫一個struct Node,編譯器只是讀取它,並不會爲它賦予內存空間.邏輯合理,它只是一個模板.

2 節點

節點由數據域和指針域構成.指針域決定先後鏈接順序,有時鏈接關係不好修改的,可以直接交換數據域的內容,間接達到交換節點的目的.

單鏈表由一個個節點構成

typedef struct node{
    datatype data;
    struct node *next;
}LNode

node LNode = {};

等價於

public class node{
    Object data;
    class node next;
}
public class LNode extends node{}

3 棧

後進先出,前插法

抽象:表L; 新節點s(malloc,s->a=x); s->next=L(指向表頭);L=s(表頭指向s,s再指向next裏保存的舊錶頭地址)

    linkList create_stack(int flag){
        linkList L = null; //linkList是指針子類,故L也是指針,又L=null靜態聲明,省去了malloc分配.
        // 同時! L==null;第一個節點s->next=L,巧妙地使最後一個節點的next爲null.不會出現野指針.
        node *s;
        int x;
        scanf("%d",&x);
        int cout=1;
        while(cout<=flag){
            s=(Node*)malloc(sizeof(node));//每次循環都會手動new一個s.因爲新的s節點的next後繼是上一節點,所以新的s節點是上一節點的前驅.即新的s節點是前插的.滿足棧後進先出的形式.
            s->data=x;
            s->next=L;//s上鍊指向L的表頭,此時s還不算在L內
            L = s;//讓s做L的表頭,即巧妙地讓L永遠指向新的表頭元素.
            scanf("%d",&x);
            cout++;
        }
        return L;
    }

4 隊列

後進後出,尾插法

表L只要指向表頭就夠了,我們可以用副表指針*r先指向第一個節點(s作表頭時),它與L都是指向第一個節點的引用.

linkList create_quene(int flag){
    linkList L=null;
    node *s,*r=null;
    int x;
    scanf("%d",&x);
    int cout=1;
    while(cout<=flag){
        s = malloc(sizeof(node)); //new一個s,new完對s的屬性賦值
        s->a = x; 
        if(L=null) L=s;
        else r->next = s;上鍊
        r = s; //此處r,L都是s的軟引用.L佔了r的光,之後一條龍的鏈表全靠r接上.L最多指向表頭,其餘上鍊操作有r來完成
        scanf("%d",&x);
        cout++;
    }
    //定義表尾節點的後繼節點爲空.
}

5 利用表指針求表長

表指針順節點往下走(賦值),表指針都是數據域爲空,指針域指向當前節點,與節點同類型的內存空間.

後插法裏的L,*r都是表指針,其中L作頭指針變量,它所引用的節點叫頭節點.即L是頭節點,L->next纔是第一個數據節點

int linkList_length(linkList L){
    node *p = L;
    int j=0;
    while(p->next!=nuLl){
        p=p->next;
        j++;
    }
    return j;
}

6 前插法與後插法

*p指向某個節點,*s指向待插入的新節點

graph LR
後插法
A(節點p)-->|起初令p->next=p',得到|B(p的下一節點是p')
A-->|最終p的下一節點是s|C
C-->|第二步p->next=s|A
C(待插入節點s)-->|第一步s->next=p`|B
graph BT
前插法
B(當前節點p)-->|第一步 q=L, while \q->next!=p\ q=q->next|A(找到p的前驅q)
C-->|第二步 s->next=p|B
A-->|第三步 q->next=s|C
C(待插入節點s)
graph TB
後插+交換實現前插
A(節點p)-->|起初 p->next=p`|B(p的下一節點是p`)
A-->|交換節點數據swap\p->next,s->next\|C
C-->|第二步p->next=s|A
C(待插入節點s)-->|第一步s->next=p`|B

7 刪除節點

當前節點p,前驅節點q

  1. 已知p,找到它的前驅q
  2. *q->next = *p->next
  3. free§

8 刪除當前節點的後一節點

當前節點*p

  1. node *s;
  2. s = p->next;
  3. p->next = s->next;
  4. free(s);

9 刪除表L的第i個元素

  1. for循環找到L[i-1]
  2. 若L[i-1]->next != null
  3. 則用刪除節點法,刪除第i個節點

10 單循環列表

  1. 尾指針指向頭指針
  2. 判斷表已經遍歷一遍的方法是p->next == head,是則已到尾指針.
  3. 有時可用r指向尾指針,直接從尾部開始遍歷,加快運算.

11 單鏈表總結

單鏈表不具備按序號隨機(直接)訪問元素的能力,必須先找到它的前驅節點,才能訪問要訪問的節點.即只能從頭指針開始訪問.

12 雙向鏈表

prior data next
typedef struct dlnode{
    datatype data;
    struct dlnode *prior,*next;
}DLnode,*DLinkList

單鏈表能做的事它都能做,最大的區別就是每修改一次鏈表,必須前後節點都要定義指向一次

12.1 插入

已知p,插入s
s->prior = p->prior;
p->prior->next = s;
p->prior = s;
s->next = p;

12.2 刪除(free)

已知p,刪除p

  1. p->prior->next = p->next;
  2. p->next->prior = p->prior;
  3. free§;

1.6 以a1爲基準,劃分線性表

劃分就是重排列,比a1小的在前,大的在後

1.7 兩線性表比較大小

A長a,B長b,兩數組第一次不同時的下標i,A的剩餘長度as,B的剩餘長度bs,

  1. for循環使下標走到兩數組第一次不同的地方,i
  2. for(j=i;j<a;j++){ AS[j-i]=A[j];a++;}
  3. for(j=i;j<b;j++){ BS[j-i]=B[j];b++;}
  4. if(asbs&&as0) return 0;//A==B
  5. if(as==0&&bs>0 || as>0&&bs>0&&AS[0]<BS[0]) return -1;//A<B
  6. else return 1;//A>B

1.8 倒轉單鏈表

將原鏈表H中的每一個元素依次作爲第一個元素插入到新鏈表中
void reverse(LinkList H){
Node *p;
p=H->next;
while§{
q=p;
p=p->next;
//插入q到頭節點後面
q->next = H->next;
H->next = q;
}
}

刪除表L中重複的元素

從首元素開始,遍歷表L,刪除與首元素相同的元素(修改鏈接關係),類推

兩層遍歷,兩層while

void pur_LinkList(LinkList H){
    Node *p,*q,*r;
    p=H->next;
    while(p->next){
        q=p;
        while(q->next){
            if(q->next->data=p->next){
                r = q->next;
                q->next=r->next;
                free(r);
        }else{
            q=q->next;//下一個對比元素
        }
        p=p->next;//下一個首元素
    }
}

按訪問權比排序鏈表元素

prior前驅指針域,data數據域,next後繼指針域,freq權比域

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