【Python資料結構】無向圖的實現及用數學思想相互轉換

Yakuho發表於2020-12-06

PS:此處使用的表示方式只是鄰接矩陣和只存半三角矩陣這兩種。
鄰接矩陣的轉化方法:

  1. 下三角列表轉化鄰接矩陣(設矩陣的階數為 N N N)
    在這裡插入圖片描述
    對於下三角而言:索引每層都是順序遞增,且第一層只含有一個元素,第二次含有兩個元素,以此類推…故只需確定起點就可由列表轉為矩陣。起點的遞增便可以理解為二階導數是1的一個函式。起點用函式表示 f ( y + 1 ) = f ( y ) + y + 1 , f ( 0 ) = 0 , 此 處 y 表 示 第 幾 行 . f(y+1)=f(y)+y+1,f(0)=0,此處y表示第幾行. f(y+1)=f(y)+y+1,f(0)=0,y.
    對於上三角而言:由於是對稱的關係起點便是變為由該層的對角元素開始,則起點函式便是 g ( x + 1 ) = g ( x ) + x + 2 , x ∈ [ 0 , N − 1 ) , g ( 0 ) = 0 , 此 處 x 表 示 第 幾 行 g(x+1)=g(x)+x+2,x∈[0, N-1),g(0)=0,此處x表示第幾行 g(x+1)=g(x)+x+2,x[0,N1),g(0)=0x,則元素的遞增元素函式 f ( y + 1 ) = f ( y ) + y + 1 , y ∈ ( x , N − 1 ) , 初 始 狀 態 下 f ( y ) = g ( x ) , 此 處 y 表 示 第 幾 列 , x 表 示 第 幾 行 f(y+1)=f(y)+y+1,y∈(x, N-1),初始狀態下f(y)=g(x),此處y表示第幾列,x表示第幾行 f(y+1)=f(y)+y+1,y(x,N1),f(y)=g(x),y,x
    時間複雜度是 O ( n ) O(n) O(n)
    • 下三角起點函式: f ( y + 1 ) = f ( y ) + y + 1 , f ( 0 ) = 0 , y ∈ [ 0 , N − 1 ) , 此 處 y 表 示 第 幾 行 f(y+1)=f(y)+y+1,f(0)=0,y∈[0,N-1),此處y表示第幾行 f(y+1)=f(y)+y+1,f(0)=0,y[0,N1),y
    • 下三角元素函式: g ( x + 1 ) = g ( x ) + 1 , x ∈ [ 0 , y − 1 ) , g ( 0 ) = f ( y ) , 此 處 x 表 示 第 幾 列 , y 表 示 第 幾 行 g(x+1)=g(x)+1, x∈[0, y-1),g(0)=f(y),此處x表示第幾列,y表示第幾行 g(x+1)=g(x)+1,x[0,y1),g(0)=f(y),x,y
    • 上三角起點函式: g ( x + 1 ) = g ( x ) + x + 2 , x ∈ [ 0 , N − 1 ) , g ( 0 ) = 0 , 此 處 x 表 示 第 幾 行 g(x+1)=g(x)+x+2,x∈[0, N-1),g(0)=0,此處x表示第幾行 g(x+1)=g(x)+x+2,x[0,N1),g(0)=0,x
    • 上三角元素函式: f ( y + 1 ) = f ( y ) + y + 1 , y ∈ ( x , N − 1 ) , 初 始 狀 態 下 f ( y ) = g ( x ) , 此 處 y 表 示 第 幾 列 , x 表 示 第 幾 行 f(y+1)=f(y)+y+1,y∈(x, N-1),初始狀態下f(y)=g(x),此處y表示第幾列,x表示第幾行 f(y+1)=f(y)+y+1,y(x,N1),f(y)=g(x),y,x
  2. 上三角列表轉化鄰接矩陣(設矩陣的階數為 N N N)
    在這裡插入圖片描述
    對於上三角而言:每層都是順序遞增的,只需確定矩陣的總階數,就可上三角元素和下三角元素進行拼接,完成轉換。由於半三角列表滿足等差數列,故總階數函式 N = f ( l e n g t h ) = 1 + 8 ∗ l e n g t h − 1 2 N=f(length)=\frac {\sqrt{1+8*length}-1}{2} N=f(length)=21+8length 1。有了總階數,就可算出每一層對角元素的值,即起點函式 g ( x + 1 ) = g ( x ) + ( N − x ) , x ∈ [ 0 , N − 1 ) , g ( 0 ) = 0 , 此 處 x 表 示 第 幾 行 g(x+1) = g(x) + (N-x),x∈[0, N-1),g(0) = 0, 此處x表示第幾行 g(x+1)=g(x)+(Nx),x[0,N1),g(0)=0,x
    對於下三角而言:起點函式 f ( y ) = y , y ∈ [ 0 , N ) , 此 處 y 表 示 第 幾 行 f(y)=y, y∈[0, N),此處y表示第幾行 f(y)=y,y[0,N),y,而該行的元素遞增是一個二階導數為-1的函式,元素函式 g ( x + 1 ) = g ( x ) + [ N − ( x − 1 ) ] , x ∈ [ 0 , y − 1 ) , 初 始 狀 態 下 g ( x ) = f ( y ) , 此 處 x 表 示 第 幾 列 , y 表 示 第 幾 行 g(x+1) = g(x) + [N-(x-1)], x∈[0, y-1), 初始狀態下g(x)=f(y), 此處x表示第幾列,y表示第幾行 g(x+1)=g(x)+[N(x1)],x[0,y1),g(x)=f(y),x,y
    時間複雜度是 O ( n ) O(n) O(n)
    • 下三角起點函式: f ( y ) = y , y ∈ [ 0 , N ) , 此 處 y 表 示 第 幾 行 f(y)=y, y∈[0, N), 此處y表示第幾行 f(y)=y,y[0,N),y
    • 下三角元素函式: g ( x + 1 ) = g ( x ) + [ N − ( x − 1 ) ] , x ∈ [ 0 , y − 1 ) , 初 始 狀 態 下 g ( x ) = f ( y ) , 此 處 x 表 示 第 幾 列 , y 表 示 第 幾 行 g(x+1) = g(x) + [N-(x-1)], x∈[0, y-1), 初始狀態下g(x)=f(y), 此處x表示第幾列,y表示第幾行 g(x+1)=g(x)+[N(x1)],x[0,y1),g(x)=f(y),x,y
    • 上三角起點函式: g ( x + 1 ) = g ( x ) + ( N − x ) , x ∈ [ 0 , N − 1 ) , g ( 0 ) = 0 , 此 處 x 表 示 第 幾 行 g(x+1) = g(x) + (N-x),x∈[0, N-1),g(0) = 0, 此處x表示第幾行 g(x+1)=g(x)+(Nx),x[0,N1),g(0)=0,x
    • 上三角元素函式: f ( y + 1 ) = f ( y ) + y + 1 , y ∈ ( x , N − 1 ) , 初 始 狀 態 下 f ( y ) = g ( x ) , 此 處 y 表 示 第 幾 列 , x 表 示 第 幾 行 f(y+1)=f(y)+y+1,y∈(x, N-1),初始狀態下f(y)=g(x),此處y表示第幾列,x表示第幾行 f(y+1)=f(y)+y+1,y(x,N1),f(y)=g(x),y,x
  3. 無論是上三角還是下三角,只需在每一行以對角元素為準,向右輸出 b b b個元素,向左輸出 a a a個元素,只要滿足 a + b + 1 = N a+b+1=N a+b+1=N即可轉換為鄰接矩陣。 設 r o w = 行 數 , 矩 陣 的 階 數 為 N 設row=行數,矩陣的階數為N row=,N
    1. a = [ 0 , r o w ] a=[0, row] a=[0,row]
    2. b = [ N − r o w − 1 , N ) b=[N-row-1, N) b=[Nrow1,N)

簡單程式碼實現:

class SymmetryGraph:
    def __init__(self, matrix, shape_type):
        """
        初始化圖
        :param matrix: 鄰接矩陣、上三角形式或下三角形式
        :param shape_type: matrix、list_up、list_down
        """
        # 圖
        self.data = matrix
        # 表示形式
        self.type = shape_type
        # 節點數
        if self.type == 'matrix':
            self.n = len(self.data)
        else:
            spot_num = ((8 * len(self.data) + 1) ** 0.5 - 1) / 2
            if spot_num == float(int(spot_num)):
                self.n = int(spot_num)
            else:
                raise TypeError('data is not a symmetry graph')

    def info(self):
        """
        顯示對稱矩陣
        :return:
        """
        print('=' * self.n * 3)
        if self.type == 'matrix':
            for i in self.data:
                print(str(i).replace(',', ' '))
        elif self.type == 'list_up':
            num = 0
            for i in range(self.n):
                row = self.data[num: num + self.n - i]
                print('[' + '   ' * (self.n - len(row)) + str(row)[1:].replace(',', ' '))
                num += self.n - i
        elif self.type == 'list_down':
            num = 0
            for i in range(self.n):
                row = self.data[num: num + i + 1]
                print(str(row)[:-1].replace(',', ' ') + '   ' * (self.n - len(row)) + ']')
                num += i + 1

    def to_convert(self, mode='list', spilt='up'):
        """
        轉化對稱矩陣為上三角或下三角陣列
        ======================================================================
            matrix = [
                [0, 0, 0, 0, 1],
                [0, 0, 1, 1, 0],
                [0, 1, 0, 1, 0],
                [0, 1, 1, 0, 1],
                [1, 0, 0, 1, 0]
            ]
            m = SymmetryGraph(matrix)
            m.to_convert(mode='list', spilt='up')    # 將對稱矩陣轉化為上三角陣列
            m.to_convert(mode='list', spilt='down')  # 將對稱矩陣轉化為下三角陣列

            matrix_up = [0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0]
            m = SymmetryGraph(matrix_up)
            m.to_convert(mode='matrix', spilt='up')    # 將上三角陣列轉化為對稱矩陣

            matrix_down = [0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0]
            m = SymmetryGraph(matrix_down)
            m.to_convert(mode='matrix', spilt='down')  # 將下三角陣列轉化為對稱矩陣
        ======================================================================
        :param mode: 轉換的目標: list, matrix
        :param spilt: 陣列的分割: up, down
        :return: None
        """
        if not self.data:
            raise TypeError('graph is empty')
        temp = list()
        if mode == 'list' and self.type == 'matrix':
            if spilt == 'up':
                for row in range(len(self.data)):
                    temp.extend(self.data[row][row:])
                self.data = temp
                self.type = 'list_up'
            elif spilt == 'down':
                for row in range(len(self.data)):
                    temp.extend(self.data[row][:row + 1])
                self.data = temp
                self.type = 'list_down'
        elif mode == 'matrix' and 'list' in self.type:
            if spilt == 'up':
                i_0, j_0 = 0, 0
                for i in range(self.n):
                    j_0 = i_0
                    temp.append(self.data[i_0: i_0 + self.n - i])
                    i_0 += self.n - i
                    for j in range(len(temp[i]), self.n):
                        j_0 = j_0 - j
                        temp[i].insert(0, self.data[j_0])
                self.data = temp
            elif spilt == 'down':
                i_0, j_0 = 0, 0
                for i in range(self.n):
                    row = list()
                    i_0 += i
                    for j1 in range(i_0, i_0 + i + 1):
                        row.append(self.data[j1])
                        j_0 = j1
                    for j2 in range(i + 1, self.n):
                        j_0 += j2
                        row.append(self.data[j_0])
                    temp.append(row)
                self.data = temp
            self.type = 'matrix'
        elif mode == 'list' and 'list' in self.type:
            self.to_convert(mode='matrix', spilt=self.type.replace('list_', ''))
            self.to_convert(mode='list', spilt=spilt)

    def conn_status(self, p1, p2):
        if self.type == 'matrix':
            return self.data[p1][p2]
        elif self.type == 'list_up':
            [p1, p2] = sorted([p1, p2])
            pos = (p1 * (2 * self.n - p1 - 1)) // 2 + p2
            return self.data[pos]
        elif self.type == 'list_down':
            [p1, p2] = sorted([p1, p2], reverse=True)
            pos = (p1 * (p1 + 1)) // 2 + p2
            return self.data[pos]
matrix0 = [
    [0, 0, 0, 0, 1, 1],
    [0, 0, 1, 1, 0, 0],
    [0, 1, 0, 1, 0, 1],
    [0, 1, 1, 0, 1, 1],
    [1, 0, 0, 1, 0, 1],
    [1, 0, 1, 1, 1, 0]
]
# matrix_down = [0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0]
# matrix_up = [0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0]
m = SymmetryGraph(matrix=matrix0, shape_type='matrix')
m.info()
m.to_convert(mode='list', spilt='down')
m.info()
m.to_convert(mode='list', spilt='up')
m.info()
status = m.conn_status(4, 0)
print('點4和點0的連通性是:', status)

執行結果

==================
[0  0  0  0  1  1]
[0  0  1  1  0  0]
[0  1  0  1  0  1]
[0  1  1  0  1  1]
[1  0  0  1  0  1]
[1  0  1  1  1  0]
==================
[0               ]
[0  0            ]
[0  1  0         ]
[0  1  1  0      ]
[1  0  0  1  0   ]
[1  0  1  1  1  0]
==================
[0  0  0  0  1  1]
[   0  1  1  0  0]
[      0  1  0  1]
[         0  1  1]
[            0  1]
[               0]4和點0的連通性是: 1

相關文章