日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【数据结构与算法】之线性表的应用和操作

發布時間:2024/5/21 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数据结构与算法】之线性表的应用和操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數據結構概念

  • 數據結構:是相互之間存在一種或多種特定關系的數據元素的集合。
  • 數據結構的邏輯結構:數據對象中數據元素之間的相互關系,分為線性結構、樹形結構、圖形結構以及集合結構。
  • 數據結構的物理結構:數據的邏輯結構在計算機中的存儲形式,分為順序存儲和鏈式存儲(不連續存儲)。
  • 算法:解決特定問題求解步驟的描述,在計算機中表現為指令的有限序列,并且每條指令表示一個或多個操作。
  • 算法五個基本特性:輸入、輸出、有窮性、確定性和可行性。
  • 算法時間復雜度O(n):常數階、線性階、平方階、對數階、立方階、nlogn階、指數階。
  • 耗時排序:O(1) < O(logn) < O(n) < O(nlgn) < O(x2) < O(x3) < O(2n) < O(n!) < O(nn)。

線性表

一、概念
  • 線性表:就是零個或者多個數據元素的有限序列,數據元素之間是一對一的關系;
  • 性質:數據元素可以為空;數據元素有限;數據元素之間的邏輯結構為線性結構,也就是一對一的關系;數據元素類型相同。
線性表的抽象數據類型: ADT 線性表(List) Data線性表的數據對象集合為{a1, a2, ......, an},每一個元素的類型都是DataType。其中,除第一個元素a1外,每一個元素有且僅有一個直接前驅元素,除了最后一個元素an外,每一個元素有且僅有一個直接后續元素。數據元素之間的關系是一對一的關系。 Operationcount:線性表元素個數。first:頭指針。last:尾指針。isEmpty():若線性表為空,返回true,否則返回false。remove():將線性表清空node(i):將線性表中的第i個位置的元素返回。insert(data,i):在線性表中的第i個位置插入新數據data。 EndADT
二、順序線性表
  • 順序線性表:使用一段連續的地址存儲單元放置線性表的數據元素。
  • 順序存儲的插入步驟:
    ① 線性表長度大于等于數組長度,拋出異常;
    ② 插入位置不合適,拋出異常(判斷插入位置與0和最大值的大小);
    ③ 從最后一個元素開始向前變量,將它們都向后移動一位;
    ④ 將要插入的元素填入指定位置;
    ⑤ 表長加一;
  • 順序存儲的刪除步驟:
    ① 線性表是否為空;
    ② 刪除位置不合適,拋出異常(判斷插入位置與0和最大值的大小);
    ③ 取出刪除元素;
    ④ 從刪除元素的位置遍歷到最后一個元素位置,將它們前移一位;
    ⑤ 表長減一;
  • 順序線性表的優缺點:
優點缺點
可以快速獲取下標的數據元素,時間復雜度為O(1)插入和刪除操作需要移動大量的元素,時間復雜度為O(n)
邏輯關系是一對一的關系,連續存儲單元足以儲存,不需要增加額外的存儲空間線性表的存儲空間大小難以確定,并且不好擴展
造成存儲空間碎片
三、鏈式線性表
  • 鏈式線性表:線性表的數據元素可以存儲在隨意的存儲單元,每一個節點不僅僅包括數據元素還有一個指向下一個節點的指針(基本的單鏈表)。
  • 鏈式(單鏈表)和順序線性表優缺點對比:
鏈式線性表順序線性表
存儲方式任意地址存儲空間一段地址連續的存儲空間
時間性能(查找)O(n)O(1)
時間性能(插入和刪除)尋找相應的節點,時間復雜度為O(n),然后,插入和刪除為O(1)O(n)
空間性能不需要提前分配空間,只要有存儲空間分配就行,數據元素個數只受可分配存儲空間大小的限制需要提前分配存儲空間,分配大了,浪費空間,分配小了,容易發生上溢
  • 鏈式線性表的基本分類:
名稱描述
單向鏈表一段地址連續的存儲空間
靜態鏈表使用順序結構實現鏈式線性表
雙向鏈表每個節點除了數據元素,還包含一個指向上一個節點的指針和一個指向下一個節點的指針
循環鏈表線性表的尾部指向頭節點,形成一個閉環
四、雙向鏈表
  • 節點定義:
public class LinkedListNode<T> {var data: T //Data could not be nil.var previous: LinkedListNode? //The pointer to previous node.var next: LinkedListNode? //The pointer to next node.init(_ data: T) {self.data = data} }
  • 雙向鏈表:head指向第一個有數據的節點,有的線性表會生成一個頭節點,該節點不存儲任何數據或者只存儲該鏈表的長度,該節點指向第一個有數據的節點。這樣做的好處就是,第一個節點的刪除和插入操作和其他節點保持一致。
public enum ErrorStatus {case Error(message: String)case OK }public class DoubleLinkedList<T> {public typealias Node = LinkedListNode<T>private var head: Node? //Head node of link list.public var isEmpty: Bool { //If link list has no data, return true.return head == nil}public var first: Node? { //Get first node is the head of link list.return head}public var last: Node? { //Last node of link list....return node}public var count: Int { //Retrun link list's nodes count....return count}public func node(atIndex index: Int) -> Node? { //Get node with index...return node}public func appendData(data: T) { //Append data to link list tail...}public func insert(data: T, atIndex index: Int) -> ErrorStatus { //Insert data at indexguard index >= 0, index <= count else {return ErrorStatus.Error(message: "Index is out of range!")}let newNode = Node(data)if index == 0 {if let node = first {head = newNodenewNode.next = nodenode.previous = newNode} else {head = newNode}} else {let node = self.node(atIndex: index-1)let nextNode = self.node(atIndex: index)node?.next = newNodenewNode.previous = nodenewNode.next = nextNodenextNode?.previous = newNode}return ErrorStatus.OK}public func remove(atIndex index: Int) -> (T?, ErrorStatus) { //Remove node at indexguard !isEmpty else {return (nil, ErrorStatus.Error(message: "Link list is Empty!"))}guard index >= 0, index < count else {return (nil, ErrorStatus.Error(message: "Index is out of range!"))}let node = self.node(atIndex: index)let nextNode = self.node(atIndex: index+1)if index == 0 {head = nextNode} else {let beforeNode = self.node(atIndex: index-1)beforeNode?.next = nextNodenextNode?.previous = beforeNode}return (node?.data, ErrorStatus.OK)} }
  • insert操作:無論insert還是remove都是先拆鏈,然后再組合成新的數據鏈。
    ① 先判斷需要插入數據的index是否在[0, count]的范圍之內,注意這里是方括號,也就是包含邊界,因為線性表最前面和最后面都可以插入新的數據;
    ② 生成新節點;
    ③ 因為這里的雙向鏈表沒有采取頭節點的方式實現,所以,插入第一個節點和其他節點有點不一樣,需要做一些判斷;
    ④ 如果是插入第一個節點,則判斷如果該鏈表為空,則直接設置head=newNode;如果該鏈表不為空,則將一個節點賦值給node,然后將newNode賦值給head,接著將node賦值給newNode.next,最后設置node.previous=newNode;
    ⑤ 如果不是插入一個節點,則先獲取下標為index-1的節點node,然后獲取下標為index的節點nextNode。設置node.next=newNode,然后newNode.next=nextNode,連成一條指向下一個數據元素的鏈,最后設置newNode.previous=node和nextNode.previous=newNode連上指向上一個數據元素的鏈,自此,先的數據插入成功;
public func insert(data: T, atIndex index: Int) -> ErrorStatus { //Insert data at indexguard index >= 0, index <= count else {return ErrorStatus.Error(message: "Index is out of range!")}let newNode = Node(data)if index == 0 {if let node = first {head = newNodenewNode.next = nodenode.previous = newNode} else {head = newNode}} else {let node = self.node(atIndex: index-1)let nextNode = self.node(atIndex: index)node?.next = newNodenewNode.next = nextNodenewNode.previous = nodenextNode?.previous = newNode}return ErrorStatus.OK }
  • remove操作:
    ① 先判斷是否是空鏈,如果是則返回,否則再判斷需要刪除數據的小表是否在合理范圍內,如果不是則返回;
    ② 判斷index是否等于0,如果是,則直接將head=secondNode;
    ③ 獲取beforeNode和nextNode,然后將beforeNode.next=nextNode,nextNode,previous=beforeNode,自此,下標為index的節點,沒有任何對象指向它,在當前函數域外就外被系統回收掉;
public func remove(atIndex index: Int) -> (T?, ErrorStatus) { //Remove node at indexguard !isEmpty else {return (nil, ErrorStatus.Error(message: "Link list is Empty!"))}guard index >= 0, index < count else {return (nil, ErrorStatus.Error(message: "Index is out of range!"))}let node = self.node(atIndex: index)let nextNode = self.node(atIndex: index+1)if index == 0 {head = nextNode} else {let beforeNode = self.node(atIndex: index-1)beforeNode?.next = nextNodenextNode?.previous = beforeNode}return (node?.data, ErrorStatus.OK) }
五、總結
  • 若線性表需要頻繁查找,很少進行插入和刪除操作時,使用順序存儲結構;反之,使用鏈式存儲結構。
  • 如果提前知道線性表需要的存儲空間,可以使用順序結構;如果不知道線性表中的數據元素變化有多大,即不確定需要多大的存儲空間,則使用鏈式存儲結構。

總結

以上是生活随笔為你收集整理的【数据结构与算法】之线性表的应用和操作的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。