線性表及其表示

1、多項式的表示

1.1 一元多項式及其運算

一元多項式:\(f(x)=a_0+a_1x+\cdots+a_{n-1}x^{n-1}+a_nx^n\)python

主要運算:多項式相加、相減、相乘等數組

如何用程序設計語言表示多項式,而且實現對多項式的操做?數據結構

1.2 如何表示多項式

  • 多項式的關鍵數組
    • 多項式項數\(n\)
    • 各項係數\(a_i\) 及指數 \(i\)

1.3 方法1:順序存儲結構直接表示

數組各份量對應多項式各項a[i]表示項\(x^i\)的係數\(a_i\)app

例如:\(f(x)=4x^5-3x^2+1\)post

表示以下圖所示:性能

兩個多現實相加:兩個數組對應份量相加spa

問題:如何表示多項式\(x+3x^{2000}\),至少要有2001個份量表示,而且20001個份量中只有兩項是非零的,這樣的表示方法是有很大問題的設計

1.4 方法2:順序存儲結構表示非零項

每一個非零項\(x_ix^i\)涉及兩個信息:係數\(a_i\)和指數\(i\)3d

能夠將一個多項式當作是一個\((a_i,i)\)二元組的集合。

用結構數組表示:數組份量是由係數\(a_i\)、指數\(i\)組成的結構,對應一個非零項

例如:\(P_1(x)=9x^{12}+15x^8+3x^2\)\(P_2(x)=26x^{19}-4x^8-13x^6+82\)

按指數大小有序存儲!

相加過程:從頭開始,比較兩個多項式當前對應項的指數

$ P1: (9,12), (15,8), (3,2) $

$ P2: (26,19), (-4,8), (-13,6), (82,0) $

$P3: (26,19) (9,12) (11,8) (-13,6) (3,2) (82,0) $

\(P_3(x)=26x^{19}+9x^{12}+11x^8-13x^6+3x^2+82\)

1.5 方法3:鏈表結構存儲非零項

鏈表中每一個結點存儲多項式中的一個非零項,包括係數和指數兩個數據域寄一個指針域

/* c語言實現 */

typedef struct PolyNode *Polynomial;
struct PolyNode{
  int coef;
  int expon;
  Polynomial link;
}
# python語言實現

class PolyNode():
  def __init__(coef, expon):
    self.coef = coef
    self.expon = expon
    self.next = None

例如:
\[ \begin{aligned} & P_1(x) = 9x^{12}+15x^8+3x^2 \\ & P_2(x) = 26x^{19}-4x^8-13x^6+82 \end{aligned} \]
鏈表存儲形式爲:

鏈表形式表現的多項式加法過程相似於前兩種方法。

2、什麼是線性表

多項式表示問題的啓示:

  1. 同一個問題能夠有不一樣的表示(存儲)方法
  2. 有一類共性問題:有序線性序列的組織和管理

「線性表(Linear List)」:由同類型數據元素構成有序序列的線性結構

  • 表中元素個數稱爲線性表的長度
  • 線性表沒有元素時,稱爲空表
  • 表起始位置稱表頭,表結束位置稱表尾

3、線性表的抽象數據類型描述

類型名稱:線性表(List)

數據對象集:線性表是\(n(\geq{0})\)個元素構成的有序序列\((a_1,a_2,\dots,a_n)\)

操做集:線性表\(L\in{List}\),整數\(i\)表示位置,元素\(X\in{ElementType\),線性表基本操做主要有:

  1. List MakeEmpty():初始化一個空線性表\(L\)
  2. ElementType FindKth( int K, List L ):根據位序\(K\),返回相應元素 ;
  3. int Find( ElementType X, List L ):在線性表\(L\)中查找\(X\)的第一次出現位置;
  4. void Insert( ElementType X, int i, List L):在位序\(i\)前插入一個新元素\(X\)
  5. void Delete( int i, List L ):刪除指定位序\(i\)的元素;
  6. int Length( List L ):返回線性表\(L\)的長度\(n\)

4、線性表的順序存儲實現

利用數組的連續存儲空間順序存放線性表的各元素

/* c語言實現 */

typedef struct LNode *List; /* 定義結構體指針 */
struct LNode{
  ElementType Data[MAXSIZE]; /* 數組類型的Data,數組最大長度爲MAXSIZE */
  int Last;
}; /* 定義結構體 */
struct LNode L; /* 聲明變量L */
List PtrL; /* 聲明結構體PtrL */

訪問下標爲\(i\)的元素:L.Data[i]PtrL->Data[i](取出PtrL所指向的結構體中包含的數據項Data[i])

線性表的長度:L.Last+1PtrL->Last+1(取出PtrL所指向的結構體中包含的數據項Last並加1)

主要操做的實現

4.1 初始化(創建空的順序表)

/* c語言實現 */

List MakeEmpty()
{
  List PtrL;
  PtrL = (List)malloc(sizeof(struct LNode)); /* 申請一個結構體 */
  PtrL->Last = -1;
  return PtrL;
}

4.2 查找

查找成功的平均比較次數爲\((n+1)/2\),平均時間性能爲\(O(n)\)

/* c語言實現 */

int Find(ElementType X, List Ptrl)
{
  int i = 0;
  while (i <= Ptrl->Last && Ptrl->Data[i] != X)
    i++;
  if (i > Ptrl->Last) return -1; /* 若是沒找到,返回-1 */
  else return i; /* 找到後返回的事存儲位置 */

4.3 插入(第\(i(I\leq{I}\leq{n+1}\))個位置上插入一個值爲\(X\)的新元素)

平均移動次數爲\(n/2\),平均時間性能爲\(O(n)\)

/* c語言實現 */

void Insert(ElementType X, int i, List PtrL)
{
  int j;
  if (Ptrl->Last == MAXSIZE - 1){ /* 表空間已滿,不能插入 */
    printf("表滿");
    return ;
  }
  if (i<1 || PtrL->Last+2){
    printf("位置不合法");
    return ;
  }
  for (j=PtrL->Last; j>=i-1; j--)
    PtrL->Data[j+1] = Ptrl->Data[j]; /*將a_i~a_n倒序向後移動*/
  PtrL->Data[i-1] = X; /* 新元素插入 */
  PtrL->Last++; /* Last仍指向最後元素 */
  return;
}

4.4 刪除(刪除表的第\(i(1\leq{i}\leq{n})\)個位置上的元素)

平均移動次數爲\((n-1)/2\),平均時間性能爲\(O(n)\)

/* c語言實現 */

void Delete(int i, List Ptrl)
{
  int j;
  if(i<1 || i>PtrL->Last+1){ /* 檢查空表及刪除位置的合法性 */
    printf("不存在第%d個元素", i);
    return ;
  }
  for (j=i, j<=Ptrl->Last; j++)
    PtrL->Data[j-1] = Ptrl->Data[j]; /* 將a_{i+1}~a_n順序向前移動*/
  Ptrl->Last--; /* Last仍指向最後元素 */
  return;
}

5、線性表的鏈式存儲實現

不要求邏輯上相鄰的兩個元素物理上也相鄰;經過「鏈」創建起數據元素之間的邏輯關係。即插入、刪除不須要移動數據元素,只須要修改「鏈」。

/* c語言實現 */

typedef struct LNode *List;
struct LNode{
  ElementType Data;
  List Next;
};
struct Londe L;
List PtrL;

5.1 求表長

時間性能爲\(O(n)\)

/* c語言實現 */

int Length(List PtrL)
{
  List p = PtrL; /* p指向表的第一個結點 */
  int j = 0;
  while (p) {
    p = p->Next;
    j++; /* 當前p指向的是第j個結點 */
  }
  return j;
}

5.2 查找:

平均時間性能爲\(O(n)\)

5.2.1 按序號查找:FindKth;

/* c語言實現 */

List FindKth(int K, List PtrL)
{
  List p = Ptrl;
  int i = 1;
  while (p != NULL && i < K){
    p = p->Next;
    i++;
  }
  if (i==K) return P; /* 找到第K個,返回指針 */
  else return NULL; /* 不然返回空 */

5.2.2 按值查找:Find

/* c語言實現 */

List Find(ElementType X, List PtrL)
{
  List p = PtrL;
  while (p != NULL && p->Data != X)
    p = p->Next;
  return p;
}
  1. 插入(在第\(i-1(1\leq{i}\leq{n+1})\)個結點後插入一個值爲\(X\)的新結點)

    1. 先構造一個新結點,用s指向;

    2. 再找到鏈表的第\(i-1\)個j結點,用\(p\)指向;
    3. 而後修改指針,插入結點(\(p\)以後插入新結點是\(s\)

/* c語言實現 */

List Insert(ElementType X, int i, List PtrL)
{
  List p, s;
  if (i == 1){ /* 新結點插入在表頭 */
    s = (List)malloc(sizeof(struct LNode)); /* 申請、填裝結點 */
    s->Data = X;
    s->Next = Ptrl;
    return s; /* 返回新表頭指針 */
  }
  p = FindKth(i-1, Ptrl); /* 查找第i-1個結點 */
  if (p == NULL){ /* 第i-1個不存在,不能插入 */
    printf("參數i錯");
    return NULL;
  }else{
    s = (List)malloc(sizeof(struct LNode)); /* 申請、填裝結點 */
    s->Data = X;
    s->Next = p->Next; /* 新結點插入在第i-1個結點的後面*/
    p->Next = s;
    return PtrL;
  }

5.3 刪除(刪除鏈表的第\(i(1\leq{i}\leq{n})\)個位置上的結點)

平均查找次數爲\(n/2\),平均時間性能爲\(O(n)\)

  1. 先找到鏈表的第\(i-1\)個結點,用\(p\)指向
  2. 再用指針\(s\)指向要被刪除的結點(\(p\)的下一個結點);
  3. 而後修改指針,刪除\(s\)所指結點;
  4. 最後釋放\(s\)所指結點的空間。

/* c語言實現 */

List Delete(int i, List PtrL)
{
  List p, s; /* 若要刪除的事表的第一個結點 */
  if (i == 1){
    s = PtrL; /* s指向第1個結點 */
    if (PtrL != NULL) PtrL = PtrL->Next; /* 從鏈表中刪除 */
    else return NULL;
    free(s); /* 釋放被刪除結點 */
    return PtrL;
  }
  p = FindKth(i-1, PtrL); /* 查找第i-1個結點 */
  if (p == NULL){
    printf("第%d個結點不存在", i-1); return NULL;
  } else if (i->Next == NUll){
    printf("第%d個結點不存在", i); return NULL;
  } else {
    s = p->Next; /* s指向第i個結點 */
    p->Next = s->Next; /* 從鏈表中刪除*/
    free(s); /* 釋放被刪除結點*/
    return PtrL;
  }

6、二元多項式的表示

咱們知道了一元多項式的表示,那麼二元多項式又該如何表示?好比,給定二元多項式:\(P(x,y)=9x^{12}y^2+4x^{12}+15x^8y^3-x^8y+3x^2\)

能夠將上述二元多項式當作關於\(x\)的一元多項式:\(P(x,y)=(9y^2+4)x^{12}+(15y^3-y)x^8+3x^2\quad(ax^{12}+bx^8+cx^2)\)

所以,上述二元多項式能夠用「複雜」鏈表表示爲下圖所示:

7、廣義表

  • 廣義表是線性表的推廣
  • 對於線性表而言,\(n\)個元素都是基本的單元素
  • 廣義表中,這些元素不只能夠是單元素也能夠是另外一個廣義表
/* c語言實現 */

typedef struct GNode *GList;
struct GNode{
  int Tag; /* 標誌域:0表示結點是單元素,1表示結點是廣義表 */
  union{ /* 字表指針域Sublist與單元素數據域Data複用,即公用存儲空間 */ 
    ElementType Data;
    Glist SubList;
  }URegion;
  Glist Next; /* 指向後繼結點 */
}

8、多重鏈表

多重鏈表:鏈表中的結點可能同時隸屬於多個鏈

  • 多重鏈表中結點的指針域會有多個,如前面例子包含了\(Next\)\(SubList\)兩個指針域;
  • 但包含兩個指針域的鏈表並不必定是多重鏈表,好比在雙線鏈表不是多重鏈表

多重鏈表有普遍的用途:基本上如樹、圖這樣相對複雜的數據結構都能夠採用多重鏈表方式實現存儲。

8.1 例1:多重鏈表表示矩陣

矩陣能夠用二維數組表示,但二維數組表示有兩個缺陷:

  1. 一是數組的大小須要事先肯定
  2. 對於「稀疏矩陣」,將形成大量的存儲空間浪費

\[ A=\begin{bmatrix} 18&0&0&0&2&0 \\ 0&27&0&0&0&0 \\ 0&0&0&0&-4&0 \\ 23&-1&0&0&0&12 \end{bmatrix} \]

\[ B=\begin{bmatrix} 0&2&11&0&0&0& \\ 3&-4&-1&0&0&0 \\ 0&0&0&9&13&0 \\ 0&-2&0&0&10&7 \\ 6&0&0&5&0&0 \\ \end{bmatrix} \]

分析:採用一種典型的多重鏈表——十字鏈表來存儲稀疏矩陣

  • 只存儲矩陣非0元素相:結點的數據域:行座標\(Row\)、列座標\(Col\)、數值\(Value\)

  • 每一個結點經過兩個指針域,把同行、同列串起來;

    • 行指針(或稱爲向右指針)Right

    • 列指針(或稱爲向下指針)Down

下圖爲矩陣A的多重鏈表圖:

用一個標識域\(Tag\)來區分頭結點和非0元素結點;

頭結點的標識值爲「Head」,矩陣非0元素結點的標識值爲「Term」。

9、Python實現-單鏈表

class Node(object):
    def __init__(self, val, p=0):
        self.data = val
        self.next = p


class LinkList(object):
    def __init__(self):
        self.head = 0

    def __getitem__(self, key):

        if self.is_empty():
            print('linklist is empty.')
            return

        elif key < 0 or key > self.getlength():
            print('the given key is error')
            return

        else:
            return self.getitem(key)

    def __setitem__(self, key, value):

        if self.is_empty():
            print('linklist is empty.')
            return

        elif key < 0 or key > self.getlength():
            print('the given key is error')
            return

        else:
            self.delete(key)
            return self.insert(key)

    def initlist(self, data):

        self.head = Node(data[0])

        p = self.head

        for i in data[1:]:
            node = Node(i)
            p.next = node
            p = p.next

    def getlength(self):

        p = self.head
        length = 0
        while p != 0:
            length += 1
            p = p.next

        return length

    def is_empty(self):

        if self.getlength() == 0:
            return True
        else:
            return False

    def clear(self):

        self.head = 0

    def append(self, item):

        q = Node(item)
        if self.head == 0:
            self.head = q
        else:
            p = self.head
            while p.next != 0:
                p = p.next
            p.next = q

    def getitem(self, index):

        if self.is_empty():
            print('Linklist is empty.')
            return
        j = 0
        p = self.head

        while p.next != 0 and j < index:
            p = p.next
            j += 1

        if j == index:
            return p.data

        else:

            print('target is not exist!')

    def insert(self, index, item):

        if self.is_empty() or index < 0 or index > self.getlength():
            print('Linklist is empty.')
            return

        if index == 0:
            q = Node(item, self.head)

            self.head = q

        p = self.head
        post = self.head
        j = 0
        while p.next != 0 and j < index:
            post = p
            p = p.next
            j += 1

        if index == j:
            q = Node(item, p)
            post.next = q
            q.next = p

    def delete(self, index):

        if self.is_empty() or index < 0 or index > self.getlength():
            print('Linklist is empty.')
            return

        if index == 0:
            q = Node('', self.head)

            self.head = q

        p = self.head
        post = self.head
        j = 0
        while p.next != 0 and j < index:
            post = p
            p = p.next
            j += 1

        if index == j:
            post.next = p.next

    def index(self, value):

        if self.is_empty():
            print('Linklist is empty.')
            return

        p = self.head
        i = 0
        while p.next != 0 and not p.data == value:
            p = p.next
            i += 1

        if p.data == value:
            return i
        else:
            return -1


l = LinkList()
l.initlist([1, 2, 3, 4, 5])
print(l.getitem(4))  # 5
l.append(6)
print(l.getitem(5))  # 6

l.insert(4, 40)
print(l.getitem(3))  # 4
print(l.getitem(4))  # 40
print(l.getitem(5))  # 5

l.delete(5)
print(l.getitem(5))  # 6

l.index(5)
相關文章
相關標籤/搜索