Python算法 —— 双指针问题

1. 用指针合并两个有序数组

指针的意思是内存空间的地址,计算机可以通过该地址找到变量的值,但Python中不存在真正意义上的指针,但可以通过数组模拟指针。

#初始化两个数组
arr1 = [1, 3, 4, 7]
arr2 = [2, 5, 6]
pointer = 0
#复制列表1作为初始化答案
ans = arr1.copy()
for i in range(0, len(arr2)):
	#pointer不能超过列表1长度
    while pointer < len(arr1):
        if arr2[i] <= arr1[pointer]:
        	#将列表2中小于列表1当前指针元素的元素放进合适的位置
            ans.insert(pointer+i, arr2[i])
            break
        else:
        	#若列表2所有元素都大于当前指针元素,则指针指向下一个元素
            pointer += 1
    else:
    	#如果列表1已经遍历完,将列表2剩下元素添加到列表1尾部
        ans = ans + arr2[i:]
        break

print(ans)

期待输出:
[1, 2, 3, 4, 5, 6, 7]

2. 二分查找

二分查找的列表必须是已经排序好的。二分查找需定义两个指针,头指针和尾指针,分别指向列表第一个和最后一个元素。先对头指针和尾指针求和除以2取整得到中间元素位置,比较查找数与中间元素是否相等,若不相等则按相应规则重新更新头指针或尾指针,以此类推。若头指针和尾指针已移动至相邻的位置,则判断查找数是否等于头指针元素或尾指针元素,若否,则列表中无此查找数。

#初始化列表
arr3 = [1, 3, 5, 9, 14, 23, 46, 57, 59, 66, 82, 97]
num = int(82)
head = 0
tail = int(len(arr3)-1)
#当头指针和尾指针不相邻时
while (tail-head) > 1:
	#获得中间元素位置
    mid = (tail + head)//2
    #若查找数在右边,则把中间元素位置赋值给头指针
    if arr3[mid] < num:
        head = mid
 	#若查找数在左边,则把中间元素位置赋值给尾指针
    if arr3[mid] > num:
        tail = mid
	#若查找数为中间元素,则把中间元素位置输出
    if arr3[mid] == num:
        print(mid)
        break
#当头指针和尾指针相邻时
else:
    if num == arr3[head]:
        print(head)
    elif num == arr3[tail]:
        print(tail)
    else:
        print("not found")

期待输出:
10

3. 链表创建

链表是指针连接的用于存储数据的数组,它的最大优点是可以有效利用零碎内存空间,并任意改变数组的长度。单链表的每个元素包含一个本身的值和指向下一个元素的指针,因为最后一个元素没有下一个数,所以它的指针为空指针,此处用-1表示。双链表和单链表类似,只是多了一个指向上一个元素的指针。

#两个列表组成单链表
#链表元素
ListValue = [1, 5, 6, 2, 4, 3]
#链表指针
ListPointer = [3, 2, -1, 5, 1, 4]
pointer = 0
#当指针不是空指针时,按指针寻找下一个元素
while pointer != -1:
    print(ListValue[pointer])
    pointer = ListPointer[pointer]

期待输出:
1
2
3
4
5
6

#二维列表组成单链表
LinkedList = [[1, 3], [5, 2], [6, -1], [2, 5], [4, 1], [3, 4]]
pointer = 0
#当指针不是空指针时,按指针寻找下一个元素
while pointer != -1:
    print(LinkedList[pointer][0])
    pointer = LinkedList[pointer][1]

期待输出:
1
2
3
4
5
6

#三个列表组成双链表
#链表元素
List = [1, 5, 6, 2, 4, 3]
#正序指针
ListRight = [3, 2, -1, 5, 1, 4]
#逆序指针
ListLeft = [-1, 4, 1, 0, 5, 3]
pointer = 0
#正向读取链表
while pointer != -1:
    print(List[pointer])
    pointer = ListRight[pointer]
#反向读取链表
pointer = ListRight.index(-1)
while pointer != -1:
    print(List[pointer])
    pointer = ListLeft[pointer]

期待输出:
1
2
3
4
5
6
6
5
4
3
2
1

#三维数组组成双链表
Linked = [[1, 3, -1], [5, 2, 4], [6, -1, 1], [2, 5, 0], [4, 1, 5], [3, 4, 3]]
pointer = 0
#正向读取链表
while pointer != -1:
    print(Linked[pointer][0])
    pointer = Linked[pointer][1]
#反向读取链表
GetList = [i[1] for i in Linked]
pointer = GetList.index(-1)
while pointer != -1:
    print(Linked[pointer][0])
    pointer = Linked[pointer][2]

期待输出:
1
2
3
4
5
6
6
5
4
3
2
1

4. 链表操作

链表操作主要是往链表增加元素和删除元素。单链表增加元素,应先在元素列表末尾增加相应的新值,而后将新值的前一个元素的指针赋给新值,最后把上一个元素的指针修改为指向列表末尾即可。双向链表增加元素过程类似,详见代码。删除元素:将要删除元素的指针赋给要删除元素的上一个元素,即完成删除过程。双链表删除元素过程类似,详见代码。

#单链表插入元素
ListValue = [1, 6, 7, 2, 4, 3]
ListPointer = [3, 2, -1, 5, 1, 4]
NewNumber = 5
#在列表末尾增加新值
ListValue.append(NewNumber)
#获得新值上一个元素的指针
pointer = ListValue.index(4)
#将上一个元素的指针赋给新值
Newpointer = ListPointer[pointer]
ListPointer.append(Newpointer)
#将上一个元素的指针修改为指向列表末尾
ListPointer[pointer] = int(len(ListValue)-1)
pointer = 0
while pointer != -1:
    print(ListValue[pointer])
    pointer = ListPointer[pointer]

期待输出:
1
2
3
4
5
6
7

#双链表增加元素
ListValue = [1, 5, 6, 2, 7 ,3]
ListRight = [3, 2, 4, 5, -1, 1]
ListLeft = [-1, 5, 1, 0, 2, 3]

num = 4
#在列表末尾增加新值
ListValue.append(num)
#添加并修改正序指针,过程类似单链表
NewRightPointer = ListRight[ListValue.index(3)]
ListRight.append(NewRightPointer)
ListRight[ListValue.index(3)] = len(ListValue)-1
#添加并修改逆序指针,过程类似单链表
NewLeftPointer = ListLeft[ListValue.index(5)]
ListLeft.append(NewLeftPointer)
ListLeft[ListValue.index(5)] = len(ListValue)-1

pointer = 0
#正向读取链表
while pointer != -1:
    print(ListValue[pointer])
    pointer = ListRight[pointer]
#反向读取链表
pointer = ListRight.index(-1)
while pointer != -1:
    print(ListValue[pointer])
    pointer = ListLeft[pointer]

期待输出:
1
2
3
4
5
6
7
7
6
5
4
3
2
1

#删除双链表元素
#将要删除元素的指针赋给要删除元素的上一个元素——正向过程
NewRightPointer = ListRight[ListValue.index(3)]
ListRight[ListValue.index(2)] = NewRightPointer
#将要删除元素的指针赋给要删除元素的上一个元素——逆向过程
NewLeftPointer = ListLeft[ListValue.index(3)]
ListLeft[ListValue.index(4)] = NewLeftPointer

pointer = 0

while pointer != -1:
    print(ListValue[pointer])
    pointer = ListRight[pointer]

pointer = ListRight.index(-1)
while pointer != -1:
    print(ListValue[pointer])
    pointer = ListLeft[pointer]

期待输出:
1
2
4
5
6
7
7
6
5
4
2
1