您的位置:首页 > 理论基础 > 数据结构算法

数据结构(1):单向链表的基本操作

2017-01-04 20:58 495 查看
建立、插入、查找、删除

/************************************************************************/
/*
单向链表(1)
qcy
2017年1月4日18:13:45
*/
/************************************************************************/

#include <iostream>
using namespace std;

typedef struct LNode
{
int data;
LNode * next;
} LNode, *Linklist;

// 递归、反向输出链表
void printReverseListRecursion(Linklist list) {
LNode * p = list;
if (p)
{
printReverseListRecursion(p->next);
cout<<p->data<<" ";
}
}

// 递归、正向输出链表
void printListRecursion(Linklist list) {
LNode * p = list;
if (p)
{
cout<<p->data<<" ";
printListRecursion(p->next);
}
else {
cout<<"\n";
}
}

// while循环 输出链表
void printList(Linklist list) {
LNode * p = list;
while (p)
{
cout<<p->data<<" ";
p = p->next;
}
cout<<"\n";
}

// 获取指定位置的指针(假设idx不会越界)
LNode * getNodePtAtIndex(Linklist list, int idx) {

LNode * p = list;
int i = 0;
while (i!=idx && p!=nullptr)
{
i++;
p = p->next;
}
return p;

}

// 查第一次出现某个指定元素的指针
LNode * getNodePtFirstFindRecursion(Linklist list, int target) {
LNode * p = list;
if (p)
{
if (p->data!=target) // 继续找
{
return getNodePtFirstFindRecursion(p->next,target);
} else { // 找到了
return p;
}
} else
{
return nullptr;
}
}

// 在首位增加一个元素
Linklist insertAtFirst(Linklist list, int data) {

// 建立一个节点
LNode * node = new LNode;
node->data = data;
node->next = list;

return node;
}

// 返回指向最后一个元素的指针(递归)
LNode * getLastElemPtRecursion(Linklist list) {
if (list) // 本身不是空的
{
if (list->next) // 下一个还不是空的,还没有到末尾
{
return getLastElemPtRecursion(list->next);
} else { // 已经到了末尾
return list; // 返回指向当前结点的指针
}
} else {
return nullptr;
}
}

// 返回指向最后一个元素的指针(非递归)
LNode * getLastElemPt(Linklist list) {
if (list) // 不为空
{
while (list->next) // 下一个不为空
{
list = list->next;
}
// 直到到末尾
return list;
} else
return nullptr;
}

// 在末尾增加一个元素
void insertAtLast(Linklist list, int data) {
LNode * newNode = new LNode;
newNode->data = data;
newNode->next = nullptr;
LNode * lastElmePt = getLastElemPt(list);
lastElmePt->next = newNode;
}

// 假设一定存在target
// 在某个元素的前面增加一个元素 (用2个指针操作)
Linklist insertElmeBeforeTarget(Linklist list, int target, int data) {

LNode * p, * q;
p = list;

// 1. 先要找到指向target元素的指针 和 指向target之前的一个元素的指针

if (p) // 不为nullptr
{
if (p->data == target) // 第一个元素就是target
{
LNode * newNode = new LNode;
newNode->data = data;
newNode->next = p; // 在list的第一个位置插入元素
return newNode;
} else {  // 不是target不在第一个元素

while (p->data!=target) // 还没有找到
{
q = p;
p = p->next;
}
// 直到找到
LNode * newNode = new LNode;
newNode->data = data;
newNode->next = p; // 接上后面的
q->next = newNode; // 接上前面的
return list;
}
}
else
return nullptr;
}

// 假设不越界
// 在指定的Idx前面增加一个元素(用2个指针操作)
Linklist insertElemBeforeIdx(Linklist list, int idx, int data) {

if (idx==0) // 在首位添加
{
return insertAtFirst(list,data);
} else {
int i = 0;

LNode *p, *q;
p = list;

while (i!=idx && p!=nullptr) // 把指针移动到指定位置
{
q = p;
p = p->next;
++i;
}

LNode * newNode = new LNode;
newNode->data = data;
newNode->next = p;
q->next = newNode;
return list;

}
}

void destroyList(Linklist list) {
if (!list)
{
return;
}
else {

LNode* p,*q;
p = list;
while (p)
{
q = p->next; // 保留下一个 --> 不然一会儿找不到
int temp = p->data;
cout<<"即将删除"<<temp<<endl;
delete p; // 删掉当前的
// cout<<"已删除"<<temp<<endl;
p = q; // 把当前的移动到下一个
}
}
}

int main () {

const int N = 10;
int iArray
= {1,2,3,4,5,6,7,8,9,10};

Linklist list,head,p;
list = new LNode;
head = list;
p = head;

// 第1个
list->data = iArray[0];
list->next = nullptr;

// 之后的
for (int i = 1;i<N;i++)
{
LNode * node = new LNode;
node->data = iArray[i];
node->next = nullptr;
p->next = node;
p = p->next;
}

printList(head);
printListRecursion(head);
printReverseListRecursion(head); cout<<"\n";

//////////////////////////////////////////////////////////////////////////
// 查
// 1. 获取最后一个元素的指针
LNode * lastElemPt = getLastElemPt(list); // 非递归做
cout<<lastElemPt->data<<endl;
cout<<getLastElemPtRecursion(list)->data<<endl; // 递归做

// 2. 获取指定位置的指针
LNode * nodeAt3 = getNodePtAtIndex(list,3);
cout<<nodeAt3->data<<endl;

// 3. 查第一次出现某个指定元素的指针 getNodePtFirstFind
LNode * nodeFisrtFind = getNodePtFirstFindRecursion(list,1000);
if (!nodeFisrtFind)
{
cout<<"没有找到"<<endl;
}

//////////////////////////////////////////////////////////////////////////
// 增
// 1. 在首位新增一个元素
head = insertAtFirst(list,777);
list = head;
printList(head);

// 2. 在末尾增加一个元素
insertAtLast(list,999);
printList(head);

// 3. 在3的前面增加一个元素555
head = insertElmeBeforeTarget(list,3,555);
list = head;
printList(head);

// 4. 在指定的位置加一个元素
head = insertElemBeforeIdx(list,4,456);
cout<<"在指定的位置加一个元素"<<endl;
printList(head);
head = insertElemBeforeIdx(list,0,123);
printList(head);

//////////////////////////////////////////////////////////////////////////
// 删除
// 没什么太大的技术难点吧

//////////////////////////////////////////////////////////////////////////
// 清空
// 和销毁没有太大的区别吧?

//////////////////////////////////////////////////////////////////////////
// 销毁
destroyList(head);

system("pause");
return 0;

}


这属于对单向链表的基本操作,应该都没有什么太大的技术难点。

为了反向输出链表,如果不用递归,可以用stack实现。
借助STL的stack。
stack.top();  // 获取顶端元素;
stack.push(); // 压栈
stack.pop(); // 弹栈
stack.empty(); // 栈是否为空
// 反向输出链表 非递归。用stack。借助stl
void printReverseList(Linklist head) {

stack<Linklist> s;
auto p = head;
while (p)
{
s.push(p);
p = p->next;
}

while (!s.empty())
{
LNode * node = s.top();
s.pop();
cout<<node->data<<" ";
}

cout<<"\n";

}


如果链表是循环链表的话,就不是用p==nullptr来判断是否结束了。
而是看p是不是等于头结点了。此时对第一个节点做特殊处理。
#include <iostream>
using namespace std;

typedef struct Node
{
int data;
Node * next;
} Node, * List;

void printList(List head) {

if (!head)
{
cout<<"list为空"<<endl;
}
else {

// 特殊处理头结点
// 输出头结点
cout<<head->data<<" ";

auto p = head->next; // 下一个

while (p!=head)
{
cout<<p->data<<" ";
p = p->next;
}

cout<<"\n";

}

}

int main () {

const int N = 10;
List head,p;
Node * node = new Node;
node->data = 1;
node->next = nullptr;
head = node;

p = head;

for ( int i = 2;i<N;i++)
{
Node * node = new Node;
node->data = i;
node->next = nullptr;
p->next = node;
p = p->next;
}

p->next = head; // 循环

printList(head);

system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 数据结构 链表