21T2-COMP9024-week02 lec02

Example:二分法

 以下递归算法搜索排序数组中的值:

search(v,a,lo,hi):
|  Input  value v
|         array a[lo..hi] of values
|  Output true if v in a[lo..hi]
|         false otherwise
|
|  mid=(lo+hi)/2
|  if lo>hi then return false
|  if a[mid]=v then
|     return true
|  else if a[mid]<v then
|     return search(v,a,mid+1,hi)
|  else
|     return search(v,a,lo,mid-1)
|  end if

[Diagram:Pic/binary-search-failed-small.png]

Cost analysis:

  • Ci = #calls to search() for array of length i
  • for best case, Cn = 1,刚好在中间
  • for   a[i..j]j<i (length=0) 数组为空
    • C0 = 0
  • for a[i..j]i≤j (length=n)
    • Cn = 1 + Cn/2   ⇒ Cn = log_{2}n

Thus, binary search is O(log_{2}n) or simply O(logn)   (why?

总共有n个元素,每次查找的区间大小就是n,n/2,n/4,…,n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数。 

由于n/2^k取整后>=1,即令n/2^k=1, 

可得k=log2n,(是以2为底,n的对数),所以时间复杂度可以表示O()=O(logn)。

相关数学公式

Exercise: Analysis of Algorithms

求复杂度

enqueue(Q,Elem):
|  Input  queue Q, element Elem
|  Output Q with Elem added at the end
|
|  Q.top=Q.top+1
|  for all i=Q.top down to 1 do
|     Q[i]=Q[i-1]
|  end for
|  Q[0]=Elem
|  return Q

Answer: O(|Q|)

binaryConversion(n):
|  Input  positive integer n
|  Output binary representation of n on a stack
|
|  create empty stack S
|  while n>0 do
|  |  push (n mod 2) onto S
|  |  n=n/2 log n
|  end while
|  return S

Answer: O(log n)

Relatives of Big-Oh

big-Omega

  • f(n) ∈ Ω(g(n)) 如果有连续的 c > 0 和连续整数 n0 ≥ 1 使得

    f(n) ≥ c·g(n)    ∀n ≥ n0

big-Theta

  • f(n) ∈ Θ(g(n)) if there are constants c',c'' > 0 and an integer constant n0 ≥ 1 such that

    c'·g(n) ≤ f(n) ≤ c''·g(n)    ∀n ≥ n0

当f(n)渐近小于或等于g(n)时,f(n)属于O(g(n))

当f(n)渐近地大于或等于g(n)时,f(n)属于Ω(g(n))

当f(n)渐近等于g(n)时,f(n)属于Θ(g(n))

  • ¼n2 ∈ Ω(n2)
    • need c > 0 and n0 ≥ 1 such that ¼n2 ≥ c·n2 for n≥n0
    • let c=¼ and n0=1
  • ¼n2 ∈ Ω(n)
    • need c > 0 and n0 ≥ 1 such that ¼n2 ≥ c·n for n≥n0
    • let c=1 and n0=4
  • ¼n2 ∈ Θ(n2)
    • since ¼n2 belongs to Ω(n2) and O(n2)

Static/Dynamic Sequences 静态 动态序列

以前我们使用数组来实现堆栈:

均匀元素的固定大小集合

可通过索引或“移动”指针访问

“固定大小”方面是一个潜在的问题:

(动态)数组有多大(大…以防万一)

如果满了怎么办?

刚性序列是另一个问题:

在数组中间插入/删除项

使用数组的问题可以通过 单独分配元素 把它们连在一起形成一条“链” 来解决

好处:

插入/删除对列表整体的影响最小

仅使用值所需的空间

要实现“元素链”,需要node包含

指向下一个节点的链接


要表示节点的链表,请执行以下操作:

我们需要一个指向第一个节点的指针

每个节点都包含指向下一个节点的指针

最后一个节点中的下一个指针为空

[Diagram:Pic/linkedList2.png]

链表比数组更灵活:

值不必在内存中相邻

只需改变指针就可以重新排列值

值的数量可以动态更改

可以按任何顺序添加或删除值

缺点:

指针操作出错并不难

每个值还需要存储指向下一个的指针

makeNode(v)
|  Input  value v
|  Output new linked list node with value v
|
|  new.value=v      // initialise data
|  new.next=NULL    // initialise link to next node
|  return new       // return pointer to new node

 Exercise: Creating a Linked List

Write pseudocode to create a linked list of three nodes with values 1, 42 and 9024.

mylist=makeNode(1) //get a new node
mylist.next=makeNode(42)
(mylist.next).next=makeNode(9024)

要访问当前节点中的数据:p.value

获取指向下一个节点的指针:p.next

要遍历链表,请执行以下操作:

将p设置为指向第一个节点(头部); 检查p指向的节点;将p改为指向下一个节点;当p到达列表末尾时停止(NULL)

Print all elements:

showLL(L):
|  Input linked list L
|
|  p=L
|  while p≠NULL do
|     print p.value
|     p=p.next
|  end while

Time complexity: O(|L|)

❖ Exercise: Traversing a linked list

What does this code do?

1  p=list
2  while p≠NULL do
3  |  print p.value
4  |  if p.next≠NULL then
5  |     p=p.next.next
6  |  else
7  |     p=NULL
8  |  end if
9  end while

每隔一个输出一个元素

如果p恰好是列表中的最后一个元素,那么p.next.next就不存在。

if语句确保我们不会试图将未定义的值赋给第5行中的指针p。

//判断next是否存在,存在把next.next赋值给p输出

❖ Exercise: Traversing a linked list

Rewrite showLL() as a recursive function.

showLL(L):
|  Input linked list L
|  if L≠NULL do
|     print L.value
|     showLL(L.next)
|  end if

Modifying a Linked List 修改链表

//在最前端插入
insertLL(L,d):
   Input  linked list L, value d
   Output L with d prepended to the list
 
   new=makeNode(d)  // create new list element
   new.next=L       // link to beginning of list
   return new       // new element is new head

O(1)

//Delete the first element:
deleteHead(L):
   Input  non-empty linked list L, value d
   Output L with head deleted
 
   return L.next    // move to second element

//Delete a specific element (recursive version):

deleteLL(L,d):
|  Input  linked list L
|  Output L with element d deleted
|
|  if L=NULL then            // element not in list
|     return L
|  else if L.value=d then    // d found at front
|     return deleteHead(L)   // delete first element 
|  else                      // delete element in tail list
|     L.next=deleteLL(L.next,d)
|  end if
|  return L

Time complexity: O(|L|)

Exercise: Implementing a Queue as a Linked List

基于链表为队列开发数据结构,以便…

元素排队需要固定的时间

元素出列需要固定的时间

Dequeue from the front …

dequeue(Q):
|  Input  non-empty queue Q
|  Output front element d, dequeued from Q
|
|  d=Q.front.value        // first element in the list
|  Q.front=Q.front.next   // move to second element
|  return d

Enqueue at the rear …

enqueue(Q,d):
|  Input queue Q
|
|  new=makeNode(d)     // create new list element      
|  Q.rear.next=new     // add to end of list
|  Q.rear=new          // link to new end of list

Comparison Array vs. Linked List

arraylinked list
insert/delete at beginningO(n)O(1)
insert/delete at endO(1)
 
O(1)
("doubly-linked" list, with pointer to rear)
insert/delete at middleO(n)O(n)
find an elementO(n)
(O(log n), if array is sorted)
O(n)
 
index a specific elementO(1)O(n)

Complexity Classes

Classes of problems:

  • P = problems for which an algorithm can compute answer in polynomial time
  • NP = includes problems for which no P algorithm is known

简单示例:检查整数n是否为素数

生成/测试n的所有可能因素

如果他们都不通过测试⇒ n是素数

生成过程很简单:

生成从2到n-1的所有数字的序列

测试也很简单:

检查下一个数字是否正好除以n

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆离Lorna

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值