二、线性结构
(一)基本概念
1.线性表
线性表是一种线性结构的数据结构,它的数据元素之间为一对一的关系
(a1,a2,a3,....,an)(a_1,a_2,a_3,....,a_n)(a1,a2,a3,....,an)
2.存储方式
线性表的逻辑结构在存储结构中的映射共有两种方式
(1)顺序结构(数组)
由于线性表的逻辑结构关系,它要求数据元素的关系必须是有一 一对应的逻辑先后顺序,这正好与数组之间有对应的关系。数组在计算机中的存储方式就是一段连续的存储空间。
(2)链式结构(链表)
链式结构与顺序结构不同的是,链式结构不需要是一段连续的存储空间,这样可以有效的利用计算机的内存空间,不过这样的话上一个元素要找到下一个元素就必须通过一个指针来指向下一个元素的地址,所以链表的一个节点必须包含两个元素,一个是数据元素,一个是存储下一个地址的指针。
(二)编程实现
1.顺序表
/*
重点:
1.数据的前移与后移临界值的判断
2.访问范围的判断
*/
#include <stdio.h>
#define MAX 10
typedef struct Sqlist {
int data[MAX];
int length;
}sqlist;
void InitSq(sqlist *s) {
s->length = 0;
}
int InsertSq(sqlist *s,int index,int data){
int flag = -1;
if(s->length == MAX || index < 0 || index > s->length )
flag = -1;
else
{
//从最后一个开始移动,以免之前的元素被覆盖
for(int i = s->length - 1;i >= index;i--)
s->data[i+1] = s->data[i];
s->data[index] = data;
s->length++;
flag = 0;
}
return flag;
}
int DeleteSq(sqlist *s,int index){
int flag = -1;
if(index < 0 || index > s->length)
flag = -1;
else
{
for(int i = index;i < s->length - 1;i++)
s->data[i] = s->data[i+1];
s->length--;
flag = 0;
}
return flag;
}
int FindSq(const sqlist s,int data){
int index = -1;
for(int i = 0;i < s.length;i++)
{
if(s.data[i] == data)
index = i;
}
return index;
}
void PrintSq(const sqlist s){
for(int i = 0;i < s.length;i++)
printf("%d",s.data[i]);
}
int main()
{
/* Write C code in this online editor and run it. */
sqlist s;
InitSq(&s);
printf("%d",InsertSq(&s,0,1));
printf("%d",InsertSq(&s,1,2));
printf("%d",InsertSq(&s,2,3));
printf("%d",InsertSq(&s,1,4));
PrintSq(s);
printf("%d",DeleteSq(&s,0));
PrintSq(s);
printf("%d",FindSq(s,1));
return 0;
}
//C++ 使用容器向量代替顺序表
#include <iostream>
#include <vector>
using namespace std;
//运算符重载
ostream& operator << (ostream& o,vector<int> v){
o << "[";
for(auto x:v)
{
o << x << ",";
}
o<< "]";
return o;
}
int main(int argc,const char *argv[])
{
vector<int> s;
s.push_back(1);
s.push_back(2);
s.push_back(3);
s.insert(s.begin(),4);
s.insert(s.begin()+2,5);
s.erase(s.begin()+1);
//迭代器
vector<int>::iterator it;
for(it = s.begin();it != s.end();it++)
cout << *it;
cout << endl << s;
return 0;
}
//java 使用ArrayList类实现顺序表
import java.util.ArrayList;
public class Main {
public static void main(String[] args){
ArrayList<Integer> a = new ArrayList<>();
a.add(1);
a.add(2);
a.add(3);
a.add(2,4);
System.out.println(a);
a.remove(3);
System.out.println(a);
}
}
2.链表
/*
重点:
1.对于指针的应用
2.访问越界的问题
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct Linklist {
int data;
struct Linklist *next;
}linklist;
linklist* findNode(linklist* head,int index){
int i = 1;
while(head && i < index - 1)
{
head = head->next;
i++;
}
return head;
}
int getLength(linklist* head){
int length = 0;
while(head)
{
head = head->next;
length++;
}
return length;
}
int insert(linklist** phead,int index,int data){
int flag = -1;
if(index < 0)
return flag;
//创建节点(动态创建):为了动态改变链表长度
linklist *node = (linklist*)malloc(sizeof(linklist));
node->data = data;
node->next = NULL;
//无链表,创建第一个节点
if(*phead == NULL)
{
*phead = node;
}
else
{
//插入在第一个节点
if(index == 1)
{
node->next = *phead;
*phead = node;
flag = 0;
}
//插入其他位置(先链接,再断链)
else
{
//先找到该节点的前一个节点
linklist* temp = findNode(*phead,index);
//如果找到了,就开始插入
if(temp)
{
//先让新节点的指针域指向被删除的节点
node->next = temp->next;
//再让被删除节点的前一个节点的指针域指向新节点
temp->next = node;
flag = 0;
}
}
}
return flag;
}
int delete(linklist** phead,int index){
int flag = -1;
if(index < 0)
return flag;
if(*phead == NULL)
flag = -1;
else
{
linklist *temp = *phead;
//删除头节点
if(index == 1)
{
*phead = (*phead)->next;
free(temp);
flag = 0;
}
//删除其他节点
else
{
linklist *temp1 = NULL;
temp = findNode(*phead,index);
//删除节点发生越界
if(temp == NULL || temp->next == NULL)
return flag;
//指向被删除节点
temp1 = temp->next;
//被删除节点的前一个节点指向被删除节点的后一个节点(删除节点)
temp->next = temp1->next;
free(temp1);
flag = 0;
}
}
return flag;
}
void print(linklist* const head){
linklist *temp = head;
while(temp)
{
printf("%d",temp->data);
temp = temp->next;
}
}
int main()
{
linklist* head = NULL;
insert(&head,1,1);
insert(&head,1,2);
insert(&head,1,3);
insert(&head,2,4);
insert(&head,3,5);
insert(&head,7,6);
insert(&head,6,6);
insert(&head,-1,2);
delete(&head,1);
delete(&head,3);
delete(&head,4);
delete(&head,4);
print(head);
return 0;
}
//C++ 链表容器list
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> head;
head.push_back(1);
head.push_back(2);
head.push_back(3);
//指定位置插入删除必须通过迭代器查找
list<int>::iterator it;
int length = 1;
for(it = head.begin();it != head.end();it++)
{
if(length == 2)
head.insert(it,4);
length++;
}
length = 1;
for(it = head.begin();it != head.end();it++)
{
if(length == 2)
head.erase(it++);
length++;
}
for(int x:head)
cout << x <<endl;
return 0;
}
//java LinkedList类实现链表
import java.util.LinkedList;
public class Main{
public static void main(String args[]){
LinkedList<Integer> head = new LinkedList<>();
head.add(1);
head.add(0,2);
head.add(1,3);
head.remove(1);
System.out.println(head);
}
}
(三)总结
以上即是大概的线性表的概念及其编程实现(C语言实现细节)。
重点
(1)线性表的两种物理结构
(2)在进行编程时,多结合计算机物理存储空间
- 插入或删除时,元素的移动
- 访问范围是否正确