双指针问题

双指针问题

  • 数组合并:合并两个有序数组
  • 二分查找:在有序数组中查找元素
  • 链表:链表的概念和应用

一.数组合并

from IPython.display import Image

Image(filename="./data/2_01.png",width=800,height=960)

output_3_0.png

arr1=[1,3,4,6,10]
arr2=[2,5,8,11]

ind=0

# ans初始化为arr1
ans=arr1.copy()

for i in range(0,len(arr2)):
    while ind<len(arr1):
        if arr2[i]<=arr1[ind]:
            ans.insert(ind+i,arr2[i])
            break
        else:
            # 如果ind指向的数比i指向的数小,则ind向后一位
            ind+=1
    else:
        # 如果arr1已遍历完,直接把剩下的arr2拼到arr1结尾
        ans=ans+arr2[i:]
ans
[1, 2, 3, 4, 5, 6, 8, 10, 11]

之所以使用ans存储arr1的值.因为直接使用arr1存储答案,在向数组中添加元素的过程中,列表内部的元素会变化,也就是说,我们丢失了arr1的原来的值.用ind调用原来列表中的元素与arr2中的元素进行比较,而向ans中插入arr2的数,就可以有效避免这个问题

二.二分查找/折半查找

Image(filename="./data/2_02.png",width=800,height=960)

output_8_0.png

numbers=[1,3,5,6,7,8,13,14,15,17,18,24,30,43,56]

head,tail=0,len(numbers)

search=int(input("Enter a number to search:"))

while tail-head>1:
    mid=(head+tail)//2
    
    if search<numbers[mid]:
        tail=mid
    if search>numbers[mid]:
        head=mid+1
    if search==numbers[mid]:
        ans=mid
        break
        
else:
    if search==numbers[head]:
        ans=head
    else:
        ans=-1
        
print(ans)
Enter a number to search: 14


7

三.链表

链表是用指针连接的用于存储数据的数组,它最大的优点在于可以有效利用零碎的内存空间

1.单链表

单链表的每个元素包含一个本身的值和一个指向下一个数的指针.因为链表的最后一个数没有下一个数,所以它的指针为空指针

Image(filename="./data/2_03.png",width=800,height=960)

output_14_0.png

方法1:两列表组成

建立单链表的第一种方法,把链表中的每一个元素存储的值存储在一个列表里,再把它们的指针存储在另一个列表里

ListValue=[1,5,6,2,4,3]
ListPointer=[3,2,-1,5,1,4]

链表的第一个元素的值是1,它在ListValue这个存储数值的数组中的小标是0,则ListPointer[0]=3,它是链表中这个元素的存储的指针,ListValue[3]=2.依次类推,直到有一个指针的值为-1,代表它的后面没有其他元素了

代码如下

ListValue=[1,5,6,2,4,3]
ListPointer=[3,2,-1,5,1,4]

head=0

print(ListValue[head])

next=ListPointer[head]

while next!=-1:
    print(ListValue[next])
    next=ListPointer[next]
1
2
3
4
5
6

方法2:数组中套数组

LinkedList=[[1,3],[5,2],[6,-1],[2,5],[4,1],[3,4]]

大数组中的每个小数组都是链表中的一个元素.每个小数组中的每一个数是这个元素存储的值,第二个数是指向下一个元素的指针.调用大数组LinkedList中的第m个小数组中的第n个元素可以是:LinkedList[m-1][n-1]

代码实现

value=0
pointer=1

LinkedList=[[1,3],[5,2],[6,-1],[2,5],[4,1],[3,4]]

head=0

print(LinkedList[head][value])
next=LinkedList[head][pointer]

while next!=-1:
    print(LinkedList[next][value])
    next=LinkedList[next][pointer]
1
2
3
4
5
6

2.双链表

Image(filename="./data/2_04.png",width=800,height=960)

output_27_0.png

双链表中的每个元素是由它的值和两个指针组成的,一个指针指向下一个元素,一个指针指向下一个元素

双链表比单链表的好处就是它可以双向遍历,也就是说,除了使用从第一个元素到最后一个元素的顺序来遍历之外,还可以从最后一个元素到第一个元素进行遍历

方法1:三列表组成

ListValue=[1,5,6,2,7,3]
ListRight=[3,2,4,5-1,1]
ListLeft=[-1,5,1,0,2,3]

方法2:数组套数组

right=1
left=2
value=0
LinkedList=[[1,3,-1],[5,2,5],[6,4,1],[2,5,0],[7,-1,2],[3,1,3]]

代码:正序输出双链表

ListValue=[1,5,6,2,7,3]
ListRight=[3,2,4,5,-1,1]
ListLeft=[-1,5,1,0,2,3]

head=ListLeft.index(-1)
print(ListValue[head])
Next=ListRight[head]

while Next>-1:
    print(ListValue[Next])
    Next=ListRight[Next]
    
print()
    
right=1
left=2
value=0
LinkedList=[[1,3,-1],[5,2,5],[6,4,1],[2,5,0],[7,-1,2],[3,1,3]]

head=0
print(LinkedList[head][value])
Next=LinkedList[head][right]

while Next>-1:
    print(LinkedList[Next][value])
    Next=LinkedList[Next][right]
1
2
3
5
6
7

1
2
3
5
6
7

代码:双向输出双链表

先把双链表按从第一个元素到最后一个元素的顺序输出一遍,再把它从最后一个元素到第一个元素输出一遍

ListValue=[1,5,6,2,7,3]
ListRight=[3,2,4,5,-1,1]
ListLeft=[-1,5,1,0,2,3]

head=ListLeft.index(-1)
print(ListValue[head])
Next=ListRight[head]

while Next>-1:
    print(ListValue[Next])
    Next=ListRight[Next]

print()

head=ListRight.index(-1)
print(ListValue[head])
Next=ListLeft[head]

while Next>-1:
    print(ListValue[Next])
    Next=ListLeft[Next]
1
2
3
5
6
7

7
6
5
3
2
1

3.单链表添加元素

由于列表中元素的排列顺序只取决于指针的顺序,而与它实际在数组中的排序无关,所以直接把新元素的值加在存储值的数组末尾即可,它是最后一个值,所以它的小标记为len(ListValue)-1

def Output(ListValue,ListRight,head):
    print(ListValue[head])
    next=ListRight[head]
    
    while next!=-1:
        print(ListValue[next])
        next=ListRight[next]
        
ListValue=[1,5,6,2,7,3]
ListRight=[3,2,4,5,-1,1]
head=0
prep=5

Output(ListValue,ListRight,head)
print()

# 向数组末尾加上新元素的值 4
ListValue.append(4)
# 加上新元素指针指向的位置(下一个元素)
ListRight.append(ListRight[prep])
# 上一个元素的指针指向新元素
ListRight[prep]=len(ListValue)-1

Output(ListValue,ListRight,head)
1
2
3
5
6
7

1
2
3
4
5
6
7

4.双链表添加元素

def Output(ListValue,ListRight,head):
    print(ListValue[head])
    next=ListRight[head]
    
    while next!=-1:
        print(ListValue[next])
        next=ListRight[next]
        
ListValue=[1,5,6,2,7,3]
ListRight=[3,2,4,5,-1,1]
ListLeft=[-1,5,1,0,2,3]
head=0
prep=5

Output(ListValue,ListRight,head)
print()

ListValue.append(4)
ListRight.append(ListRight[prep])
ListLeft.append(prep)
# 将前后元素的指针指向新元素
ListLeft[ListRight[prep]]=len(ListValue)-1
ListRight[prep]=len(ListValue)-1

Output(ListValue,ListRight,head)
1
2
3
5
6
7

1
2
3
4
5
6
7
ListRight[prep]
6

5.删除列表中的元素

Image(filename="./data/2_05.png",width=800,height=960)

output_46_0.png

def Output(ListValue,ListRight,head):
    print(ListValue[head])
    next=ListRight[head]
    
    while next!=-1:
        print(ListValue[next])
        next=ListRight[next]
        
ListValue=[1,5,6,2,7,3]
ListRight=[3,2,4,5,-1,1]
head=0
prep=5

Output(ListValue,ListRight,head)
print()

# 删除元素
ListRight[prep]=ListRight[ListRight[prep]]

Output(ListValue,ListRight,head)
1
2
3
5
6
7

1
2
3
6
7

6.双链表删除元素

ListValue=[1,5,6,2,7,3]
ListRight=[3,2,4,5,-1,1]
ListLeft=[-1,5,1,0,2,3]
head=0
prep=5

# 把前一个元素的right指针指向后一个元素
ListRight[prep]=ListRight[ListRight[prep]]
# 把后一个元素的left指针指向前一个元素
ListLeft[ListRight[ListRight[prep]]]=prep

Output(ListValue,ListRight,head)
1
2
3
6
7
原文地址:https://www.cnblogs.com/LQ6H/p/12940562.html