双指针问题
双指针问题
- 数组合并:合并两个有序数组
- 二分查找:在有序数组中查找元素
- 链表:链表的概念和应用
一.数组合并
from IPython.display import Image
Image(filename="./data/2_01.png",width=800,height=960)
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)
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)
方法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)
双链表中的每个元素是由它的值和两个指针组成的,一个指针指向下一个元素,一个指针指向下一个元素
双链表比单链表的好处就是它可以双向遍历,也就是说,除了使用从第一个元素到最后一个元素的顺序来遍历之外,还可以从最后一个元素到第一个元素进行遍历
方法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)
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