提示:以下是本篇文章正文内容,下面案例可供参考
1. 시퀀스 테이블
시퀀스 테이블은 데이터 요소가 연속적인 물리적 주소를 가진 저장 단위에 순차적으로 저장되는 선형 구조이며 일반적으로 어레이에 저장됩니다. 어레이의 데이터를 추가, 삭제, 확인 및 수정합니다.
정적 시퀀스 테이블(배열)과 동적 시퀀스 테이블(동적 개발)의 두 가지 구현 방법이 있습니다.
배열의 크기가 고정되어 있기 때문에 공간을 낭비하기 쉬우므로 동적 시퀀스 테이블이 더 나은 선택입니다.
인터페이스 구현
SeqList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;
int size; // 记录存储多少个有效数据
int capacity; // 空间容量大小
}SL;
void SLPrint(SL* ps);
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLCheckCapacity(SL* ps);
// 尾插尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
// 头插头删
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
// 中间插入删除
// 在pos位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
// 删除pos位置数据
void SLErase(SL* ps, int pos);
//int SLFind(SL* ps, SLDataType x);
// begin查找x的起始位置
int SLFind(SL* ps, SLDataType x, int begin);
SeqList.c
#include "SeqList.h"
void SLInit(SL* ps)
{
assert(ps);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
void SLCheckCapacity(SL* ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
int newcapacity = ((ps->capacity == 0) ? 4 : 2 * ps->capacity);
SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType) * 2);
if (tmp==NULL)
{
perror("realloc fail!");
exit(-1);
}
ps->capacity = newcapacity;
ps->a = tmp;
}
}
void SLPushBack(SL* ps, SLDataType x)
{
//assert(ps);
//SLCheckCapacity(ps);
//ps->a[ps->size] = x;
//ps->size++;
SLInsert(ps, ps->size, x);
}
void SLPopBack(SL* ps)
{
//assert(ps);
//assert(ps->size > 0);
//ps->a[ps->size - 1] = 0;
//ps->size--;
SLErase(ps, ps->size - 1);
}
void SLPushFront(SL* ps, SLDataType x)
{
//assert(ps);
//SLCheckCapacity(ps);
//int i = 0;
//for (i = ps->size - 1; i >= 0; i--)
//{
// ps->a[i+1] = ps->a[i];
//}
//ps->a[0] = x;
//ps->size++;
SLInsert(ps, 0, x);
}
void SLPopFront(SL* ps)
{
//assert(ps);
//assert(ps->size > 0);
//int i = 0;
//for (i = 1; i < ps->size; i++)
//{
// ps->a[i - 1] = ps->a[i];
//}
//ps->size--;
SLErase(ps, 0);
}
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0);
assert(pos <= ps->size);
SLCheckCapacity(ps);
int i = ps->size - 1;
for (i = ps->size - 1; i >= pos; i--)
{
ps->a[i + 1] = ps->a[i];
}
ps->a[pos] = x;
ps->size++;
}
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0);
assert(pos < ps->size);
int i = pos+1;
for (i = pos+1; i < ps->size; i++)
{
ps->a[i - 1] = ps->a[i];
}
ps->size--;
}
void SLPrint(SL* ps)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
void SLDestroy(SL* ps)
{
assert(ps);
if (ps->a)
{
free(ps->a);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
}
int SLFind(SL* ps, SLDataType x, int begin)
{
assert(ps);
int i = 0;
for (i = begin; i < ps->size; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
주제
배열 nums 및 값 val이 주어지면 값이 val과 동일한 모든 요소를 제자리에서 제거하고 제거된 배열의 새 길이를 반환해야 합니다.
추가 배열 공간을 사용하지 마십시오. O(1) 추가 공간만 사용하고 입력 배열을 제자리에서 수정해야 합니다.
요소의 순서를 변경할 수 있습니다. 새 길이를 초과하는 배열의 요소를 고려할 필요가 없습니다.
int removeElement(int* nums, int numsSize, int val){
int right=0;
int left=0;
for(right=0;right<numsSize;right++)
{
if(nums[right]!=val)
{
nums[left]=nums[right];
left++;
}
}
return left;
}
배열 번호가 오름차순으로 주어지면 각 요소가 한 번만 나타나도록 제자리에서 반복되는 요소를 삭제하고 삭제된 배열의 새 길이를 반환하십시오. 요소의 상대적 순서는 일관되어야 합니다.
일부 언어에서는 배열의 길이를 변경할 수 없으므로 결과는 배열 nums의 첫 번째 부분에 배치해야 합니다. 더 정식으로, 중복을 제거한 후 k 요소가 있는 경우 nums의 첫 번째 k 요소가 최종 결과를 보유해야 합니다.
nums의 처음 k 위치에 최종 결과를 삽입한 후 k를 반환합니다.
추가 공간을 사용하는 대신 입력 배열을 제자리에서 수정해야 하며 O(1) 추가 공간을 사용하여 수정해야 합니다.
int removeDuplicates(int* nums, int numsSize){
int fast=0;
int slow=0;
while(fast<numsSize)
{
if(nums[fast]==nums[slow])
{
fast++;
}
else
{
slow++;
nums[slow]=nums[fast];
fast++;
}
}
return slow+1;
}
둘, 연결된 목록
연결 리스트는 물리적 저장 구조에서 비연속적이고 비순차적인 저장 구조로, 데이터 요소의 논리적 순서는 연결 리스트에서 포인터의 연결 순서를 통해 구현된다.
인터페이스 구현
1. 단일 연결 리스트
슬리스트.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x);
//在pos之前插入值
void SListInsert(SListNode** pphead, SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);
//删除pos位置的值
void SListErase(SListNode** pphead, SListNode* pos);
// 单链表的销毁
void SListDestroy(SListNode** plist);
SListNode* CreateSList(int n);
슬리스트.c
#include "Slist.h"
SListNode* BuySListNode(SLTDateType x)
{
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
SListNode* CreateSList(int n)
{
SListNode* phead = NULL, * ptail = NULL;
int i = 0;
for (i = 0; i < n; i++)
{
SListNode* newnode = BuySListNode(i);
if (phead == NULL)
{
phead = ptail = newnode;
}
else
{
ptail->next = newnode;
ptail = newnode;
}
}
return phead;
}
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur != NULL)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("NULL");
}
void SListPushBack(SListNode** pplist, SLTDateType x)
{
SListNode* newnode = BuySListNode(x);
if (*pplist == NULL)
{
*pplist = newnode;
}
else
{
SListNode* tail = *pplist;
while (tail->next)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SListPopBack(SListNode** pplist)
{
assert(*pplist);
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SListNode* prev = NULL;
SListNode* tail = *pplist;
while (tail->next)
{
prev = tail;
tail = tail->next;
}
free(tail);
prev->next = NULL;
}
}
void SListPushFront(SListNode** pplist, SLTDateType x)
{
SListNode* newnode = BuySListNode(x);
newnode->next = *pplist;
*pplist = newnode;
}
void SListPopFront(SListNode** pplist)
{
assert(*pplist);
SListNode* next = *pplist;
free(*pplist);
*pplist = next;
}
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
assert(plist);
SListNode* cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
//在pos后插入数据
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* newnode = BuySListNode(x);
SListNode* next = pos->next;
pos->next = newnode;
newnode->next = next;
}
//在pos之前插入值
void SListInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{
assert(pos);
if (*pphead == pos)
{
SListPushFront(pphead, x);
}
else
{
SListNode* newnode = BuySListNode(x);
SListNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = newnode;
newnode->next = pos;
}
}
void SListEraseAfter(SListNode* pos)
{
assert(pos);
if (pos->next == NULL)
{
return;
}
else
{
SListNode* nextnode = pos->next;
pos->next = nextnode->next;
free(nextnode);
}
}
//删除pos位置的值
void SListErase(SListNode** pphead, SListNode* pos)
{
assert(pos);
assert(*pphead);
if (pos == *pphead)
{
SListPopFront(pphead);
}
else
{
SListNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
}
}
void SListDestroy(SListNode** pplist)
{
SListNode* cur = *pplist;
while (cur)
{
SListNode* next = cur->next;
free(cur);
cur = next;
}
*pplist = NULL;
}
2. 센티넬 비트가 있는 이중 연결 리스트
List.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next;
struct ListNode* prev;
LTDataType data;
}LTNode;
LTNode* BuyListNode(LTDataType x);
LTNode* LTInit();
void LTPrint(LTNode* phead);
void LTPushBack(LTNode* phead, LTDataType x);
void LTPopBack(LTNode* phead);
void LTPushFront(LTNode* phead, LTDataType x);
void LTPopFront(LTNode* phead);
LTNode* LTFind(LTNode* phead, LTDataType x);
//在pos之前插入
void LTInsert(LTNode* pos, LTDataType x);
void LTErase(LTNode* pos);
bool LTEmpty(LTNode* phead);
size_t LTSize(LTNode* phead);
void LTDestroy(LTNode* phead);
List.c
#include "List.h"
LTNode* BuyListNode(LTDataType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc fail");
exit(-1);
}
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
LTNode* LTInit()
{
LTNode* phead = BuyListNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
void LTPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
/*LTNode* newnode = BuyListNode(x);
LTNode* prev = phead->prev;
phead->prev = newnode;
newnode->next = phead;
newnode->prev = prev;
prev->next = newnode;*/
LTInsert(phead, x);
}
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
/*LTNode* tail = phead->prev;
phead->prev = tail->prev;
tail->prev->next = phead;
free(tail);*/
LTErase(phead->prev);
}
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
/*LTNode* newnode = BuyListNode(x);
LTNode* head = phead->next;
phead->next = newnode;
newnode->prev = phead;
newnode->next = head;
head->prev = newnode;*/
LTInsert(phead->next, x);
}
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
/*LTNode* first = phead->next;
LTNode* second = first->next;
phead->next = second;
second->prev = phead;
free(first);*/
LTErase(phead->next);
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
//在pos之前插入
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = BuyListNode(x);
LTNode* prev = pos->prev;
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
//删除pos位置的值
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* prev = pos->prev;
LTNode* next = pos->next;
prev->next = next;
next->prev = prev;
free(pos);
}
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
size_t LTSize(LTNode* phead)
{
assert(phead);
size_t size = 0;
LTNode* cur = phead->next;
while (cur != phead)
{
size++;
cur = cur->next;
}
return size;
}
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
주제
다음은 보다 포괄적인 질문입니다.
길이가 n인 연결 목록이 주어지면 각 노드에는 연결된 목록의 모든 노드 또는 빈 노드를 가리킬 수 있는 추가 임의 포인터 random이 포함됩니다.
이 연결된 목록의 전체 복사본을 구성합니다. 깊은 복사는 정확히 n개의 완전히 새로운 노드로 구성되어야 하며, 각 새 노드의 값은 해당하는 원래 노드의 값으로 설정됩니다. 새 노드의 다음 포인터와 임의 포인터도 복사된 연결 목록의 새 노드를 가리켜야 원본 연결 목록과 복사된 연결 목록의 포인터가 동일한 연결 목록 상태를 나타낼 수 있습니다. 복사된 연결 목록의 포인터는 원래 연결 목록의 노드를 가리키면 안 됩니다.
예를 들어 원래 연결 목록에 두 개의 노드 X와 Y가 있는 경우 X.random --> Y입니다. 그런 다음 복사 연결 목록의 해당 두 노드 x 및 y도 x.random --> y를 갖습니다.
복사된 목록의 헤드 노드를 반환합니다.
입력/출력의 연결 목록은 n 노드의 연결 목록으로 표시됩니다. 각 노드는 [val, random_index]로 표현된다:
val: Node.val을 나타내는 정수.
random_index: 임의 포인터가 가리키는 노드의 인덱스(범위는 0에서 n-1까지), 어떤 노드도 가리키지 않으면 null입니다.
귀하의 코드는 들어오는 매개 변수로 원래 연결된 목록의 헤드 노드 헤드만 허용합니다.
내 아이디어 제공:
- 각 노드 뒤에 복사 노드를 삽입하여 이전 노드와 동일한 값을 저장하는 것이 좋습니다.
- 복사 노드에서 무작위로 가리키는 노드는 소스 노드의 무작위 노드 다음 노드입니다.
- 연결 리스트를 다시 만들고 위에서 복사한 노드를 새로운 연결 리스트에 계속해서 삽입합니다.
struct Node* copyRandomList(struct Node* head) {
struct Node* cur=head;
//复制节点
while(cur)
{
struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
struct Node* next=cur->next;
copy->val=cur->val;
cur->next=copy;
copy->next=next;
cur=next;
}
cur=head;
//复制random
while(cur)
{
struct Node* copy=cur->next;
if(cur->random==NULL)
{
copy->random=NULL;
}
else
{
copy->random=cur->random->next;
}
cur=cur->next->next;
}
struct Node* copyhead=NULL,*copytail=NULL;
cur=head;
//复制节点单独拿出来
while(cur)
{
struct Node* copy=cur->next;
struct Node* next=copy->next;
cur->next=next;
if(copyhead==NULL)
{
copyhead=copytail=copy;
}
else
{
copytail->next=copy;
copytail=copytail->next;
}
cur=next;
}
return copyhead;
}